Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Optimize MemoryAllocator and add allocarray()
Browse files Browse the repository at this point in the history
  • Loading branch information
jdemeyer committed Jul 8, 2015
1 parent 9597eec commit f514301
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 53 deletions.
15 changes: 10 additions & 5 deletions src/sage/ext/memory_allocator.pxd
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from sage.ext.memory cimport malloc, free, realloc, check_calloc, check_allocarray, check_realloc, check_reallocarray
cimport cython

@cython.final
cdef class MemoryAllocator:
cdef size_t n
cdef size_t max_size
cdef size_t size
cdef void ** pointers
cdef void * malloc(self, size_t size) except NULL
cdef void * calloc(self, size_t nmemb, size_t size) except NULL
cdef enlarge_if_needed(self) except -1
cdef void * static_pointers[16] # If n <= 16, store pointers here

cdef void * malloc(self, size_t size) except? NULL
cdef void * calloc(self, size_t nmemb, size_t size) except? NULL
cdef void * allocarray(self, size_t nmemb, size_t size) except? NULL
cdef int resize(self, size_t new_size) except -1
cdef inline int enlarge_if_needed(self) except -1
89 changes: 74 additions & 15 deletions src/sage/ext/memory_allocator.pyx
Original file line number Diff line number Diff line change
@@ -1,26 +1,69 @@
from sage.ext.memory cimport *
include 'sage/ext/interrupt.pxi'

cdef class MemoryAllocator:
r"""
An object with for memory allocation, whose resources are freed upon __dealloc__.
An object for memory allocation, whose resources are freed upon
``__dealloc__``.
EXAMPLES::
sage: cython(
....: '''
....: from sage.ext.memory_allocator cimport MemoryAllocator
....: cdef MemoryAllocator mem = MemoryAllocator()
....: for n in range(100):
....: mem.malloc(n)
....: mem.calloc(n, n)
....: mem.allocarray(n, n)
....: ''')
"""
def __cinit__(self):
"""
EXAMPLES::
sage: cython(
....: '''
....: from sage.ext.memory_allocator cimport MemoryAllocator
....: cdef MemoryAllocator mem = MemoryAllocator.__new__(MemoryAllocator)
....: mem.malloc(10000)
....: print(mem.n)
....: print(mem.size)
....: ''')
1
16
"""
self.n = 0
self.max_size = 0
self.pointers = NULL
self.size = 16
self.pointers = self.static_pointers

cdef int resize(self, size_t new_size) except -1:
r"""
Resize the list of pointers to contain ``new_size`` elements.
It is required that ``new_size`` is at least ``self.n``, but
this condition is not checked.
"""
cdef size_t i
if self.pointers == self.static_pointers:
# Case 1: allocate pointers for the first time
self.pointers = <void **>check_allocarray(new_size, sizeof(void*))
for i in range(self.n):
self.pointers[i] = self.static_pointers[i]
else:
# Case 2: resize pointers
self.pointers = <void **>check_reallocarray(self.pointers, new_size, sizeof(void*))
self.size = new_size

cdef int enlarge_if_needed(self) except -1:
cdef inline int enlarge_if_needed(self) except -1:
r"""
Enlarge the list of local pointer.
Enlarge the list of pointers if needed such that there is at
least one free entry.
"""
if self.n < self.max_size:
return
cdef int new_max_size = 2*self.max_size if self.max_size else 1
cdef void ** new_pointers = <void **> check_realloc(self.pointers, new_max_size*sizeof(void*))
self.pointers = new_pointers
self.max_size = new_max_size
if unlikely(self.n >= self.size):
return self.resize(self.size * 2)

cdef void * malloc(self, size_t size) except NULL:
cdef void * malloc(self, size_t size) except? NULL:
r"""
Returns a new pointer and stores it to be automatically freed later.
"""
Expand All @@ -30,7 +73,7 @@ cdef class MemoryAllocator:
self.n += 1
return val

cdef void * calloc(self, size_t nmemb, size_t size) except NULL:
cdef void * calloc(self, size_t nmemb, size_t size) except? NULL:
r"""
Returns a new pointer and stores it to be automatically freed later.
"""
Expand All @@ -40,11 +83,27 @@ cdef class MemoryAllocator:
self.n += 1
return val

cdef void * allocarray(self, size_t nmemb, size_t size) except? NULL:
r"""
Returns a new pointer and stores it to be automatically freed later.
"""
self.enlarge_if_needed()
cdef void * val = check_allocarray(nmemb, size)
self.pointers[self.n] = val
self.n += 1
return val

def __dealloc__(self):
r"""
Free the allocated resources
EXAMPLES::
sage: from sage.ext.memory_allocator import MemoryAllocator
sage: _ = MemoryAllocator()
"""
cdef size_t i
for i in range(self.n):
free(self.pointers[i])
free(self.pointers)
sage_free(self.pointers[i])
if self.pointers != self.static_pointers:
sage_free(self.pointers)
6 changes: 3 additions & 3 deletions src/sage/graphs/asteroidal_triples.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ def is_asteroidal_triple_free(G, certificate=False):

# ==> Initialize some data structures for is_asteroidal_triple_free_C
cdef MemoryAllocator mem = MemoryAllocator()
cdef uint32_t * waiting_list = <uint32_t *> mem.malloc(n * sizeof(uint32_t))
cdef uint32_t * _connected_structure = <uint32_t *> mem.calloc(n * n , sizeof(uint32_t))
cdef uint32_t ** connected_structure = <uint32_t **> mem.malloc(n * sizeof(uint32_t *))
cdef uint32_t * waiting_list = <uint32_t *> mem.allocarray(n, sizeof(uint32_t))
cdef uint32_t * _connected_structure = <uint32_t *> mem.calloc(n * n, sizeof(uint32_t))
cdef uint32_t ** connected_structure = <uint32_t **> mem.allocarray(n, sizeof(uint32_t *))

# Copying the whole graph to obtain the list of neighbors quicker than by
# calling out_neighbors. This data structure is well documented in the
Expand Down
22 changes: 11 additions & 11 deletions src/sage/graphs/chrompoly.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@ def chromatic_polynomial(G, return_tree_basis = False):
nedges = G.num_edges()

cdef MemoryAllocator mem = MemoryAllocator()
queue = <int *> mem.malloc(nverts * sizeof(int))
chords1 = <int *> mem.malloc((nedges - nverts + 1) * sizeof(int))
chords2 = <int *> mem.malloc((nedges - nverts + 1) * sizeof(int))
parent = <int *> mem.malloc(nverts * sizeof(int))
bfs_reorder = <int *> mem.malloc(nverts * sizeof(int))
tot = <mpz_t *> mem.malloc((nverts+1) * sizeof(mpz_t))
coeffs = <mpz_t *> mem.malloc((nverts+1) * sizeof(mpz_t))
queue = <int *> mem.allocarray(nverts, sizeof(int))
chords1 = <int *> mem.allocarray((nedges - nverts + 1), sizeof(int))
chords2 = <int *> mem.allocarray((nedges - nverts + 1), sizeof(int))
parent = <int *> mem.allocarray(nverts, sizeof(int))
bfs_reorder = <int *> mem.allocarray(nverts, sizeof(int))
tot = <mpz_t *> mem.allocarray((nverts+1), sizeof(mpz_t))
coeffs = <mpz_t *> mem.allocarray((nverts+1), sizeof(mpz_t))
num_chords = 0

# Breadth first search from 0:
Expand Down Expand Up @@ -209,10 +209,10 @@ cdef int contract_and_count(int *chords1, int *chords2, int num_chords, int nver
mpz_add_ui(tot[nverts], tot[nverts], 1)
return 0
cdef MemoryAllocator mem = MemoryAllocator()
cdef int *new_chords1 = <int *> mem.malloc(num_chords * sizeof(int))
cdef int *new_chords2 = <int *> mem.malloc(num_chords * sizeof(int))
cdef int *ins_list1 = <int *> mem.malloc(num_chords * sizeof(int))
cdef int *ins_list2 = <int *> mem.malloc(num_chords * sizeof(int))
cdef int *new_chords1 = <int *> mem.allocarray(num_chords, sizeof(int))
cdef int *new_chords2 = <int *> mem.allocarray(num_chords, sizeof(int))
cdef int *ins_list1 = <int *> mem.allocarray(num_chords, sizeof(int))
cdef int *ins_list2 = <int *> mem.allocarray(num_chords, sizeof(int))
cdef int i, j, k, x1, xj, z, num, insnum, parent_checked
for i from 0 <= i < num_chords:
# contract chord i, and recurse
Expand Down
12 changes: 6 additions & 6 deletions src/sage/graphs/distances_all_pairs.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ cdef inline all_pairs_shortest_path_BFS(gg,
bitset_init(seen, n)

# The list of waiting vertices, the beginning and the end of the list
cdef int * waiting_list = <int *> mem.malloc(n*sizeof(int))
cdef int * waiting_list = <int *> mem.allocarray(n, sizeof(int))
cdef int waiting_beginning = 0
cdef int waiting_end = 0

Expand All @@ -197,7 +197,7 @@ cdef inline all_pairs_shortest_path_BFS(gg,

cdef unsigned short * c_predecessors = predecessors
cdef int * c_eccentricity = eccentricity
cdef int * c_distances = <int *> mem.malloc( n * sizeof(int))
cdef int * c_distances = <int *> mem.allocarray(n, sizeof(int))

# Copying the whole graph to obtain the list of neighbors quicker than by
# calling out_neighbors
Expand Down Expand Up @@ -1525,8 +1525,8 @@ def floyd_warshall(gg, paths = True, distances = False):
cdef int w_int

# init dist
t_dist = <unsigned short *> mem.malloc(n*n*sizeof(unsigned short))
dist = <unsigned short **> mem.malloc(n*sizeof(unsigned short *))
t_dist = <unsigned short *> mem.allocarray(n*n, sizeof(unsigned short))
dist = <unsigned short **> mem.allocarray(n, sizeof(unsigned short *))
dist[0] = t_dist
for 1 <= i< n:
dist[i] = dist[i-1] + n
Expand All @@ -1539,8 +1539,8 @@ def floyd_warshall(gg, paths = True, distances = False):

if paths:
# init prec
t_prec = <unsigned short *> mem.malloc(n*n*sizeof(unsigned short))
prec = <unsigned short **> mem.malloc(n*sizeof(unsigned short *))
t_prec = <unsigned short *> mem.allocarray(n*n, sizeof(unsigned short))
prec = <unsigned short **> mem.allocarray(n, sizeof(unsigned short *))
prec[0] = t_prec
for 1 <= i< n:
prec[i] = prec[i-1] + n
Expand Down
18 changes: 9 additions & 9 deletions src/sage/graphs/graph_decompositions/bandwidth.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,15 @@ def bandwidth(G, k=None):

cdef MemoryAllocator mem = MemoryAllocator()

cdef unsigned short ** d = <unsigned short **> mem.malloc( n * sizeof(unsigned short *))
cdef unsigned short * distances = <unsigned short *> mem.malloc( n*n * sizeof(unsigned short ))
cdef index_t * current = <index_t *> mem.malloc( n * sizeof(index_t))
cdef index_t * ordering = <index_t *> mem.malloc( n * sizeof(index_t))
cdef index_t * left_to_order = <index_t *> mem.malloc( n * sizeof(index_t))
cdef index_t * index_array_tmp = <index_t *> mem.malloc( n * sizeof(index_t))
cdef range_t * range_arrays = <range_t *> mem.malloc( n*n * sizeof(range_t))
cdef range_t ** ith_range_array = <range_t **> mem.malloc( n * sizeof(range_t *))
cdef range_t * range_array_tmp = <range_t *> mem.malloc( n * sizeof(range_t))
cdef unsigned short ** d = <unsigned short **> mem.allocarray(n, sizeof(unsigned short *))
cdef unsigned short * distances = <unsigned short *> mem.allocarray(n*n, sizeof(unsigned short ))
cdef index_t * current = <index_t *> mem.allocarray(n, sizeof(index_t))
cdef index_t * ordering = <index_t *> mem.allocarray(n, sizeof(index_t))
cdef index_t * left_to_order = <index_t *> mem.allocarray(n, sizeof(index_t))
cdef index_t * index_array_tmp = <index_t *> mem.allocarray(n, sizeof(index_t))
cdef range_t * range_arrays = <range_t *> mem.allocarray(n*n, sizeof(range_t))
cdef range_t ** ith_range_array = <range_t **> mem.allocarray(n, sizeof(range_t *))
cdef range_t * range_array_tmp = <range_t *> mem.allocarray(n, sizeof(range_t))

cdef int i,j,kk
all_pairs_shortest_path_BFS(G,NULL,distances,NULL) # compute the distance matrix
Expand Down
4 changes: 2 additions & 2 deletions src/sage/graphs/hyperbolicity.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,8 @@ cdef inline distances_and_far_apart_pairs(gg,

# The list of waiting vertices
cdef MemoryAllocator mem = MemoryAllocator()
cdef uint32_t * waiting_list = <uint32_t *> mem.malloc(n * sizeof(uint32_t))
cdef unsigned short ** c_far_apart = <unsigned short **> mem.malloc(n * sizeof(unsigned short*))
cdef uint32_t * waiting_list = <uint32_t *> mem.allocarray(n, sizeof(uint32_t))
cdef unsigned short ** c_far_apart = <unsigned short **> mem.allocarray(n, sizeof(unsigned short*))

# The vertices which have already been visited
cdef bitset_t seen
Expand Down
4 changes: 2 additions & 2 deletions src/sage/graphs/mcqd.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ def mcqd(G):
# - c points toward each row of the matrix
# - qmax stores the max clique
cdef MemoryAllocator mem = MemoryAllocator()
cdef bool ** c = <bool **> mem.malloc(n*sizeof(bool *))
cdef bool ** c = <bool **> mem.allocarray(n, sizeof(bool *))
cdef bool * c0 = <bool *> mem.calloc(n*n, sizeof(bool))
cdef int * qmax = <int *> mem.malloc(n*sizeof(int))
cdef int * qmax = <int *> mem.allocarray(n, sizeof(int))

c[0] = c0

Expand Down

0 comments on commit f514301

Please sign in to comment.