ยปCore Development>Code coverage>Python/pyarena.c

Python code coverage for Python/pyarena.c

#countcontent
1n/a#include "Python.h"
2n/a
3n/a/* A simple arena block structure.
4n/a
5n/a Measurements with standard library modules suggest the average
6n/a allocation is about 20 bytes and that most compiles use a single
7n/a block.
8n/a
9n/a TODO(jhylton): Think about a realloc API, maybe just for the last
10n/a allocation?
11n/a*/
12n/a
13n/a#define DEFAULT_BLOCK_SIZE 8192
14n/a#define ALIGNMENT 8
15n/a
16n/atypedef struct _block {
17n/a /* Total number of bytes owned by this block available to pass out.
18n/a * Read-only after initialization. The first such byte starts at
19n/a * ab_mem.
20n/a */
21n/a size_t ab_size;
22n/a
23n/a /* Total number of bytes already passed out. The next byte available
24n/a * to pass out starts at ab_mem + ab_offset.
25n/a */
26n/a size_t ab_offset;
27n/a
28n/a /* An arena maintains a singly-linked, NULL-terminated list of
29n/a * all blocks owned by the arena. These are linked via the
30n/a * ab_next member.
31n/a */
32n/a struct _block *ab_next;
33n/a
34n/a /* Pointer to the first allocatable byte owned by this block. Read-
35n/a * only after initialization.
36n/a */
37n/a void *ab_mem;
38n/a} block;
39n/a
40n/a/* The arena manages two kinds of memory, blocks of raw memory
41n/a and a list of PyObject* pointers. PyObjects are decrefed
42n/a when the arena is freed.
43n/a*/
44n/a
45n/astruct _arena {
46n/a /* Pointer to the first block allocated for the arena, never NULL.
47n/a It is used only to find the first block when the arena is
48n/a being freed.
49n/a */
50n/a block *a_head;
51n/a
52n/a /* Pointer to the block currently used for allocation. It's
53n/a ab_next field should be NULL. If it is not-null after a
54n/a call to block_alloc(), it means a new block has been allocated
55n/a and a_cur should be reset to point it.
56n/a */
57n/a block *a_cur;
58n/a
59n/a /* A Python list object containing references to all the PyObject
60n/a pointers associated with this area. They will be DECREFed
61n/a when the arena is freed.
62n/a */
63n/a PyObject *a_objects;
64n/a
65n/a#if defined(Py_DEBUG)
66n/a /* Debug output */
67n/a size_t total_allocs;
68n/a size_t total_size;
69n/a size_t total_blocks;
70n/a size_t total_block_size;
71n/a size_t total_big_blocks;
72n/a#endif
73n/a};
74n/a
75n/astatic block *
76n/ablock_new(size_t size)
77n/a{
78n/a /* Allocate header and block as one unit.
79n/a ab_mem points just past header. */
80n/a block *b = (block *)PyMem_Malloc(sizeof(block) + size);
81n/a if (!b)
82n/a return NULL;
83n/a b->ab_size = size;
84n/a b->ab_mem = (void *)(b + 1);
85n/a b->ab_next = NULL;
86n/a b->ab_offset = (char *)_Py_ALIGN_UP(b->ab_mem, ALIGNMENT) -
87n/a (char *)(b->ab_mem);
88n/a return b;
89n/a}
90n/a
91n/astatic void
92n/ablock_free(block *b) {
93n/a while (b) {
94n/a block *next = b->ab_next;
95n/a PyMem_Free(b);
96n/a b = next;
97n/a }
98n/a}
99n/a
100n/astatic void *
101n/ablock_alloc(block *b, size_t size)
102n/a{
103n/a void *p;
104n/a assert(b);
105n/a size = _Py_SIZE_ROUND_UP(size, ALIGNMENT);
106n/a if (b->ab_offset + size > b->ab_size) {
107n/a /* If we need to allocate more memory than will fit in
108n/a the default block, allocate a one-off block that is
109n/a exactly the right size. */
110n/a /* TODO(jhylton): Think about space waste at end of block */
111n/a block *newbl = block_new(
112n/a size < DEFAULT_BLOCK_SIZE ?
113n/a DEFAULT_BLOCK_SIZE : size);
114n/a if (!newbl)
115n/a return NULL;
116n/a assert(!b->ab_next);
117n/a b->ab_next = newbl;
118n/a b = newbl;
119n/a }
120n/a
121n/a assert(b->ab_offset + size <= b->ab_size);
122n/a p = (void *)(((char *)b->ab_mem) + b->ab_offset);
123n/a b->ab_offset += size;
124n/a return p;
125n/a}
126n/a
127n/aPyArena *
128n/aPyArena_New()
129n/a{
130n/a PyArena* arena = (PyArena *)PyMem_Malloc(sizeof(PyArena));
131n/a if (!arena)
132n/a return (PyArena*)PyErr_NoMemory();
133n/a
134n/a arena->a_head = block_new(DEFAULT_BLOCK_SIZE);
135n/a arena->a_cur = arena->a_head;
136n/a if (!arena->a_head) {
137n/a PyMem_Free((void *)arena);
138n/a return (PyArena*)PyErr_NoMemory();
139n/a }
140n/a arena->a_objects = PyList_New(0);
141n/a if (!arena->a_objects) {
142n/a block_free(arena->a_head);
143n/a PyMem_Free((void *)arena);
144n/a return (PyArena*)PyErr_NoMemory();
145n/a }
146n/a#if defined(Py_DEBUG)
147n/a arena->total_allocs = 0;
148n/a arena->total_size = 0;
149n/a arena->total_blocks = 1;
150n/a arena->total_block_size = DEFAULT_BLOCK_SIZE;
151n/a arena->total_big_blocks = 0;
152n/a#endif
153n/a return arena;
154n/a}
155n/a
156n/avoid
157n/aPyArena_Free(PyArena *arena)
158n/a{
159n/a assert(arena);
160n/a#if defined(Py_DEBUG)
161n/a /*
162n/a fprintf(stderr,
163n/a "alloc=%d size=%d blocks=%d block_size=%d big=%d objects=%d\n",
164n/a arena->total_allocs, arena->total_size, arena->total_blocks,
165n/a arena->total_block_size, arena->total_big_blocks,
166n/a PyList_Size(arena->a_objects));
167n/a */
168n/a#endif
169n/a block_free(arena->a_head);
170n/a /* This property normally holds, except when the code being compiled
171n/a is sys.getobjects(0), in which case there will be two references.
172n/a assert(arena->a_objects->ob_refcnt == 1);
173n/a */
174n/a
175n/a Py_DECREF(arena->a_objects);
176n/a PyMem_Free(arena);
177n/a}
178n/a
179n/avoid *
180n/aPyArena_Malloc(PyArena *arena, size_t size)
181n/a{
182n/a void *p = block_alloc(arena->a_cur, size);
183n/a if (!p)
184n/a return PyErr_NoMemory();
185n/a#if defined(Py_DEBUG)
186n/a arena->total_allocs++;
187n/a arena->total_size += size;
188n/a#endif
189n/a /* Reset cur if we allocated a new block. */
190n/a if (arena->a_cur->ab_next) {
191n/a arena->a_cur = arena->a_cur->ab_next;
192n/a#if defined(Py_DEBUG)
193n/a arena->total_blocks++;
194n/a arena->total_block_size += arena->a_cur->ab_size;
195n/a if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE)
196n/a ++arena->total_big_blocks;
197n/a#endif
198n/a }
199n/a return p;
200n/a}
201n/a
202n/aint
203n/aPyArena_AddPyObject(PyArena *arena, PyObject *obj)
204n/a{
205n/a int r = PyList_Append(arena->a_objects, obj);
206n/a if (r >= 0) {
207n/a Py_DECREF(obj);
208n/a }
209n/a return r;
210n/a}