source: trunk/lib/allocator.hpp @ 1938

Last change on this file since 1938 was 1938, checked in by ksherdy, 7 years ago

Fixed aligned_allocation memory corruption. Updated both aligned and
unaligned implementation to follow identical logic.

File size: 4.0 KB
Line 
1/*
2 * allocator.hpp - Memory allocation.
3 * Created on: 18-December-2011
4 * Author: Ken Herdy
5 *
6 *
7 */
8
9
10#ifndef ALLOCATOR_HPP_
11#define ALLOCATOR_HPP_
12
13#include "debug.hpp"
14#include "bitblock.hpp"
15#include <assert.h>
16#include <stdint.h>
17#include <stdlib.h>
18
19#include <iostream>
20using namespace std;
21
22/* Base Class */
23class pool_allocator {
24public:
25        /* n - bytes requested, allocd_segment_size - bytes allocated */
26        void * allocate (uint64_t n, uint64_t & allocd_segment_size);
27        void * allocate_aligned (uint64_t n, uint64_t & allocd_segment_size);
28        void destroy ();
29protected:
30        pool_allocator(){}
31        ~pool_allocator(){}
32};
33
34/* Fast Memory Pool Allocator - Trade memory for speed.
35 *
36 * Allocates BASE_SIZE bytes on the stack. Analogous to BUFFER_SIZE in the Pablo template.
37 * Allocates additional bytes on the heap.
38 * Coterminal deallocation.
39 * Allocation returns void * pointer to memory block, returns number of bytes allocated.
40 *
41 */
42template<uint32_t BASE_SIZE>
43class fast_pool_allocator : public pool_allocator {
44
45public:
46        fast_pool_allocator(const uint8_t align=64, const uint8_t exp=2): ALIGNMENT(align), EXPANSION_FACTOR(exp) {
47                tail = &head;
48                tail->segment = stack_segment;
49                tail->next = NULL;
50                available = BASE_SIZE;
51                segment_size = BASE_SIZE;
52        }
53
54        ~fast_pool_allocator() {}
55
56        void * allocate(uint64_t n, uint64_t & allocd_segment_size) {
57
58                if(n > available) {
59                        segment_size = next_segment_size(n);
60
61                        node * next = (node *) malloc(sizeof(node));
62                        if (next == NULL) {
63                                cerr << "Out of Memory" << endl;
64                                abort();
65                        }
66
67                        next->segment = (uint8_t *) malloc(segment_size);
68                        if ((next->segment) == NULL) {
69                                cerr << "Out of Memory" << endl;
70                                abort();
71                        }
72
73                        next->next = NULL;
74                        tail->next = next;
75                        tail = next;
76
77                        uint64_t address = reinterpret_cast<uint64_t>(&(tail->segment[0]));
78                        allocd_segment_size = segment_size;
79                        available = 0;
80
81                        return (void *) (address);
82                }
83
84                uint32_t i = segment_size - available;
85                uint64_t address = reinterpret_cast<uint64_t>(&(tail->segment[i]));
86
87                allocd_segment_size = n;
88                available -= n;
89
90                return (void *) (address);
91        }
92
93        void * allocate_aligned(uint64_t n, uint64_t & allocd_segment_size) {
94
95                uint64_t n_padded = (n+ALIGNMENT-1);
96
97                cout << "BOO " << n_padded << ":" << available << endl;
98
99                if(n_padded > available) {
100
101                        segment_size = next_segment_size(n_padded);
102
103                        node * next = (node *) malloc(sizeof(node));
104                        if (next == NULL) {
105                                cerr << "Out of Memory" << endl;
106                                abort();
107                        }
108
109                        next->segment = (uint8_t *) malloc(segment_size);
110                        if ((next->segment) == NULL) {
111                                cerr << "Out of Memory" << endl;
112                                abort();
113                        }
114
115                        next->next = NULL;
116                        tail->next = next;
117                        tail = next;
118
119                        uint64_t address = reinterpret_cast<uint64_t>(&(tail->segment[0]));
120                        uint64_t padding = ((address % ALIGNMENT) == 0) ? 0 :  ALIGNMENT - (address % ALIGNMENT);
121                        allocd_segment_size = segment_size - padding;
122                        available = 0;
123
124                        assert(((uint64_t)(address + padding))%ALIGNMENT == 0);
125                        return (void *) (address + padding);
126                }
127
128                uint32_t i = segment_size - available;
129                uint64_t address = reinterpret_cast<uint64_t>(&(tail->segment[i]));
130                uint64_t padding = ((address % ALIGNMENT) == 0) ? 0 :  ALIGNMENT - (address % ALIGNMENT);
131                allocd_segment_size = n - padding;
132                available -= (padding + n);
133
134                assert(((uint64_t)(address + padding))%ALIGNMENT == 0);
135
136                return (void *) (address + padding);
137        }
138
139        void destroy() {
140                node * crt = head.next;
141                node * next;
142                while(crt != NULL) {
143                        next = crt->next;
144                        free((uint8_t *) crt->segment);
145                        free((node *)crt);
146                        crt = next;
147                        next = NULL;
148                }
149        }
150
151        uint64_t get_alloc_size() const { return alloc_size; }
152
153private:
154        uint64_t alloc_size;
155
156        const uint8_t ALIGNMENT;
157        const uint8_t EXPANSION_FACTOR;
158        uint64_t available;
159        uint64_t segment_size;
160
161        typedef struct node {
162                node * next;
163                uint8_t * segment;
164        } node;
165
166        uint8_t stack_segment[BASE_SIZE];
167        node head;
168        node * tail;
169
170        uint64_t next_segment_size(uint64_t n) const {
171                return (((n/segment_size) * segment_size) + segment_size) * EXPANSION_FACTOR ; // a multiple of segment_size
172        }
173
174};
175
176#endif
Note: See TracBrowser for help on using the repository browser.