ARB
PT_mem.h
Go to the documentation of this file.
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)
49 const char *get_blocksize_description(int blocksize); // declare this elsewhere
50 #endif
51 
52 
53 class MemBlock : virtual Noncopyable {
54  char *data;
55  MemBlock *next;
56 public:
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 
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 
107 class 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 
115 public:
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 
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  }
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 
209 class 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 
240 public:
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 
306 struct 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 
315 extern Memory MEM;
316 
317 #else
318 #error PT_mem.h included twice
319 #endif // PT_MEM_H
bool contains(char *somemem, int blocksize) const
Definition: PT_mem.h:83
void * PT_PNTR
Definition: PT_tools.h:24
static GB_ERROR tab(GBL_command_arguments *args, bool pretab)
Definition: adlang1.cxx:913
#define PTM_MAX_SIZE
Definition: PT_mem.h:44
void fflush_all()
Definition: PT_tools.h:211
#define PTM_TABLE_COUNT
Definition: PT_mem.h:41
Memory()
Definition: PT_mem.h:242
MemBlock(int size, MemBlock *&prev)
Definition: PT_mem.h:57
#define PTM_magic
Definition: PT_mem.h:46
~MemBlock()
Definition: PT_mem.h:65
void clear()
Definition: PT_mem.h:196
void PT_write_pointer(void *toMem, const void *thePtr)
Definition: PT_tools.h:206
TYPE * ARB_alloc(size_t nelem)
Definition: arb_mem.h:56
void GBK_terminate(const char *error) __ATTR__NORETURN
Definition: arb_msg.cxx:463
#define true
Definition: ureadseq.h:14
bool is_clear() const
Definition: PT_mem.h:189
char * get_block(int forsize)
Definition: PT_mem.h:137
const char * GBS_readable_size(unsigned long long size, const char *unit_suffix)
Definition: arb_misc.cxx:23
static int idx2size(int idx)
Definition: PT_mem.h:121
fputc('\n', stderr)
GB_write_int const char GB_write_autoconv_string WRITE_SKELETON(write_pointer, GBDATA *,"%p", GB_write_pointer) char *AW_awa if)(!gb_var) return strdup("")
Definition: AW_awar.cxx:166
~MemBlockManager()
Definition: PT_mem.h:133
#define pt_assert(bed)
Definition: PT_tools.h:22
#define PTM_MIN_SIZE
Definition: PT_mem.h:35
#define PTM_ELEMS_PER_BLOCK
Definition: PT_mem.h:42
void clear()
Definition: PT_mem.h:298
const char * get_blocksize_description(int blocksize)
Memory MEM
Definition: PT_main.cxx:128
Definition: PT_mem.h:209
void put(void *vblock, int size)
Definition: PT_mem.h:272
#define NULp
Definition: cxxforward.h:97
static ED4_block block
Definition: ED4_block.cxx:73
bool contains(const CONT &container, const KEY &key)
bool is_clear() const
Definition: PT_mem.h:297
char * get_memory()
Definition: PT_mem.h:81
static int size2idx(int forsize)
Definition: PT_mem.h:120