source: tags/ms_r18q1/PROBE/PT_mem.h

Last change on this file was 16763, checked in by westram, 6 years ago
File size: 8.4 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : PT_mem.h                                          //
4//   Purpose   : memory handling for ptserver                      //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in October 2012   //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#ifndef PT_MEM_H
13#define PT_MEM_H
14
15#ifndef ARBTOOLS_H
16#include <arbtools.h>
17#endif
18#ifndef ARB_CORE_H
19#include <arb_core.h>
20#endif
21#ifndef PT_TOOLS_H
22#include "PT_tools.h"
23#endif
24#ifndef ARB_MISC_H
25#include <arb_misc.h>
26#endif
27
28#define PTM_MANAGED_MEMORY // comment-out to use malloc/free => can use valgrind
29
30#if defined(PTM_MANAGED_MEMORY)
31// # define PTM_MEM_DUMP_STATS
32// #  define PTM_MEM_CHECKED_FREE // careful: slow as hell!
33#endif
34
35#define PTM_MIN_SIZE (int(sizeof(PT_PNTR))+1) // see .@PTM_MIN_SIZE_RESTRICTED
36
37#if defined(PTM_MANAGED_MEMORY)
38
39#define PTM_TABLE_SIZE  (1024*256)
40
41#define PTM_TABLE_COUNT     256
42#define PTM_ELEMS_PER_BLOCK 256
43
44#define PTM_MAX_SIZE (PTM_TABLE_COUNT+PTM_MIN_SIZE-1)
45
46#define PTM_magic 0xf4
47
48#if defined(PTM_MEM_DUMP_STATS)
49const char *get_blocksize_description(int blocksize); // declare this elsewhere
50#endif
51
52
53class MemBlock : virtual Noncopyable {
54    char     *data;
55    MemBlock *next;
56public:
57    MemBlock(int size, MemBlock*& prev)
58        : data(ARB_alloc<char>(size)),
59          next(prev)
60    {
61        if (!data) GBK_terminate("out of memory");
62        prev = NULp;
63    }
64
65    ~MemBlock() {
66        if (next) {
67            MemBlock *del = next;
68            next          = NULp;
69
70            while (del) {
71                MemBlock *n = del->next;
72                del->next   = NULp;
73
74                delete del;
75                del = n;
76            }
77        }
78        free(data);
79    }
80
81    char *get_memory() { return data; }
82
83    bool contains(char *somemem, int blocksize) const {
84        pt_assert(somemem);
85        pt_assert(blocksize>0);
86        return
87            (somemem >= data && somemem < (data+blocksize))
88            ||
89            (next && next->contains(somemem, blocksize));
90    }
91
92#if defined(PTM_MEM_DUMP_STATS)
93    size_t count() const {
94        const MemBlock *b = this;
95       
96        size_t cnt = 1;
97        while (b->next) {
98            b = b->next;
99            ++cnt;
100        }
101
102        return cnt;
103    }
104#endif
105};
106
107class MemBlockManager : virtual Noncopyable {
108    MemBlock *block[PTM_TABLE_COUNT];
109    long      allsize;
110
111    static int blocksize4size(int forsize) {
112        return forsize * PTM_ELEMS_PER_BLOCK;
113    }
114
115public:
116#if defined(PTM_MEM_DUMP_STATS)
117    bool dump_stats;
118#endif
119
120    static int size2idx(int forsize) { return forsize-PTM_MIN_SIZE; }
121    static int idx2size(int idx) { return idx+PTM_MIN_SIZE; }
122
123    MemBlockManager()
124        : allsize(0)
125#if defined(PTM_MEM_DUMP_STATS)
126        , dump_stats(true)
127#endif
128    {
129        for (int b = 0; b<PTM_TABLE_COUNT; ++b) {
130            block[b] = NULp;
131        }
132    }
133    ~MemBlockManager() {
134        clear();
135    }
136
137    char *get_block(int forsize) {
138        int allocsize = blocksize4size(forsize);
139        int tab       = size2idx(forsize);
140
141        block[tab]  = new MemBlock(allocsize, block[tab]);
142        allsize    += allocsize;
143
144        return block[tab]->get_memory();
145    }
146
147#if defined(PTM_MEM_CHECKED_FREE)
148    bool block_has_size(char *vblock, int size) const {
149        int tab = size2idx(size);
150        if (block[tab]) {
151            if (block[tab]->contains(vblock, blocksize4size(size))) {
152                return true;
153            }
154        }
155        return false;
156    }
157#endif
158
159#if defined(PTM_MEM_DUMP_STATS)
160    void dump_max_memory_usage(FILE *out) const {
161        fflush_all();
162        long sum = 0;
163        for (int b = 0; b<PTM_TABLE_COUNT; ++b) {
164            if (block[b]) {
165                int    size           = idx2size(b);
166                size_t blocks         = block[b]->count();
167                size_t allocated4size = blocks * blocksize4size(size);
168                int    elemsPerBlock  = blocksize4size(size)/size;
169                size_t maxElements    = blocks*elemsPerBlock;
170                int    percent        = double(allocated4size)/double(allsize)*100+0.5;
171
172                fprintf(out, "blocksize: %2i  allocated: %7s [~%2i%%]  ", size, GBS_readable_size(allocated4size, "b"), percent);
173                fprintf(out, "<~%12s", GBS_readable_size(maxElements, "Blocks"));
174
175                const char *desc = get_blocksize_description(size);
176                if (desc) fprintf(out, " [%s]", desc);
177
178                fputc('\n', out);
179
180                sum += allocated4size;
181            }
182        }
183        fprintf(out, "sum of above:  %s\n", GBS_readable_size(sum, "b"));
184        fprintf(out, "overall alloc: %s\n", GBS_readable_size(allsize, "b"));
185        fflush_all();
186    }
187#endif
188
189    bool is_clear() const {
190        for (int b = 0; b<PTM_TABLE_COUNT; ++b) {
191            if (block[b]) return false;
192        }
193        return true;
194    }
195
196    void clear() {
197#if defined(PTM_MEM_DUMP_STATS)
198        if (dump_stats) dump_max_memory_usage(stderr);
199#endif
200        for (int b = 0; b<PTM_TABLE_COUNT; ++b) {
201            delete block[b];
202            block[b] = NULp;
203        }
204        allsize = 0;
205    }
206
207};
208
209class Memory : virtual Noncopyable {
210    MemBlockManager  manager;
211    char            *free_data[PTM_TABLE_COUNT];
212
213    void alloc_new_blocks(int forsize) {
214        int tab = MemBlockManager::size2idx(forsize);
215        pt_assert(!free_data[tab]);
216
217        char *prevPos = NULp;
218        {
219            char *block = manager.get_block(forsize);
220            char *wp    = block;
221
222            for (int b = 0; b<PTM_ELEMS_PER_BLOCK; ++b) {
223                PT_write_pointer(wp, prevPos);
224                wp[sizeof(PT_PNTR)] = PTM_magic;
225
226                prevPos  = wp;
227                wp      += forsize;
228            }
229        }
230
231        free_data[tab] = prevPos;
232    }
233
234    void clear_tables() {
235        for (int t = 0; t < PTM_TABLE_COUNT; ++t) {
236            free_data[t] = NULp;
237        }
238    }
239
240public:
241
242    Memory() { clear_tables(); }
243
244#if defined(PTM_MEM_DUMP_STATS)
245    void dump_stats(bool dump) { manager.dump_stats = dump; }
246#endif
247
248    void *get(int size) {
249        pt_assert(size >= PTM_MIN_SIZE);
250
251        if (size > PTM_MAX_SIZE) {
252            return ARB_calloc<char>(size);
253        }
254
255        int   tab = MemBlockManager::size2idx(size);
256        char *erg = free_data[tab];
257        if (!erg) {
258            alloc_new_blocks(size);
259            erg = free_data[tab];
260        }
261
262        pt_assert(erg);
263        free_data[tab] = PT_read_pointer<char>(free_data[tab]);
264        memset(erg, 0, size);
265        return erg;
266    }
267
268#if defined(PTM_MEM_CHECKED_FREE)
269    bool block_has_size(void *vblock, int size) { return manager.block_has_size((char*)vblock, size); }
270#endif
271
272    void put(void *vblock, int size) {
273        pt_assert(size >= PTM_MIN_SIZE);
274
275        char *block = (char*)vblock;
276        if (size > PTM_MAX_SIZE) {
277            free(block);
278        }
279        else {
280#if defined(PTM_MEM_CHECKED_FREE)
281            if (!block_has_size(vblock, size)) {
282                for (int idx = 0; idx<PTM_TABLE_COUNT; ++idx) {
283                    int isize = manager.idx2size(idx);
284                    if (isize != size && block_has_size(vblock, isize)) {
285                        pt_assert(size == isize);
286                    }
287                }
288            }
289#endif
290            int tab = MemBlockManager::size2idx(size);
291            PT_write_pointer(block, free_data[tab]); // Note: PTM_MIN_SIZE_RESTRICTED by amount written here
292            block[sizeof(PT_PNTR)] = PTM_magic;
293            free_data[tab] = block;
294        }
295    }
296
297    bool is_clear() const { return manager.is_clear(); }
298    void clear() {
299        clear_tables();
300        manager.clear();
301        pt_assert(is_clear());
302    }
303};
304#else // !defined(PTM_MANAGED_MEMORY)
305
306struct Memory { // plain version allowing to use memory-checker
307    void clear() {}
308    bool is_clear() const { return true; }
309    void *get(int size) { return ARB_calloc<char>(size); } // @@@ use ARB_alloc and initialize objects instead, then stop cleaning memory in Memory
310    void put(void *block, int) { free(block); }
311};
312
313#endif
314
315extern Memory MEM;
316
317#else
318#error PT_mem.h included twice
319#endif // PT_MEM_H
Note: See TracBrowser for help on using the repository browser.