GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
mm.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * MODULE: iostream
4  *
5 
6  * COPYRIGHT (C) 2007 Laura Toma
7  *
8  *
9 
10  * Iostream is a library that implements streams, external memory
11  * sorting on streams, and an external memory priority queue on
12  * streams. These are the fundamental components used in external
13  * memory algorithms.
14 
15  * Credits: The library was developed by Laura Toma. The kernel of
16  * class STREAM is based on the similar class existent in the GPL TPIE
17  * project developed at Duke University. The sorting and priority
18  * queue have been developed by Laura Toma based on communications
19  * with Rajiv Wickremesinghe. The library was developed as part of
20  * porting Terraflow to GRASS in 2001. PEARL upgrades in 2003 by
21  * Rajiv Wickremesinghe as part of the Terracost project.
22 
23  *
24  * This program is free software; you can redistribute it and/or modify
25  * it under the terms of the GNU General Public License as published by
26  * the Free Software Foundation; either version 2 of the License, or
27  * (at your option) any later version.
28  *
29 
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
33  * General Public License for more details. *
34  * **************************************************************************/
35 
36 
37 
38 // A simple registration based memory manager.
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <assert.h>
43 #include <iostream>
44 using std::cout;
45 using std::cerr;
46 using std::endl;
47 
48 //#include <mm.h>
49 #include <grass/iostream/mm.h>
50 
51 #define MM_DEBUG if(0)
52 
53 
54 
55 /* ************************************************************ */
57 
58  instances++;
59  if (instances > 1) {
60  cerr << "MM_register(): Only 1 instance of MM_register should exist.\n";
61  assert(0); //core dump if debugging
62  exit(1);
63  }
64  assert(instances == 1);
65 
66  // by default, we ignore if memory limit is exceeded
67  register_new = MM_IGNORE_MEMORY_EXCEEDED;
68 }
69 
70 
71 
72 /* ************************************************************ */
74 
75  if (instances > 1) {
76  cerr << "MM_register(): Only 1 instance of MM_register should exist.\n";
77  assert(0); //core dump if debugging
78  exit(1);
79  }
80  assert(instances == 1);
81  instances--;
82 }
83 
84 
85 /* ************************************************************ */
87 
88  size_t availMB = (remaining >> 20);
89  if (remaining) {
90  cout << "available memory: " << availMB << "MB "
91  << "(" << remaining << "B)"
92  << endl;
93  } else {
94  cout << "available memory: " << remaining << "B, exceeding: "
95  << used - user_limit << "B"
96  << endl;
97  }
98 }
99 
100 
101 /* ************************************************************ */
102 // User-callable method to set allowable memory size
104 
105  assert( new_limit > 0);
106  if (used > new_limit) {
107  // return MM_ERROR_EXCESSIVE_ALLOCATION;
108  switch (register_new) {
110  cerr << " MM_register::set_memory_limit to " << new_limit
111  << ", used " << used << ". allocation exceeds new limit.\n";
112  cerr.flush();
113  assert(0); //core dump if debugging
114  exit(1);
115  break;
116 
118  cerr << " MM_register::set_memory_limit to " << new_limit
119  << ", used " << used << ". allocation exceeds new limit.\n";
120  break;
121 
123  break;
124  }
125  user_limit = new_limit;
126  remaining = 0;
127  return MM_ERROR_NO_ERROR;
128  }
129 
130  assert(used <= new_limit);
131  // These are unsigned, so be careful.
132  if (new_limit < user_limit) {
133  remaining -= user_limit - new_limit;
134  } else {
135  remaining += new_limit - user_limit;
136  }
137  user_limit = new_limit;
138  return MM_ERROR_NO_ERROR;
139 }
140 
141 
142 
143 /* ************************************************************ */
144 //only warn if memory limit exceeded
146  register_new = MM_WARN_ON_MEMORY_EXCEEDED;
147 }
148 
149 
150 /* ************************************************************ */
151 //abort if memory limit exceeded
153  register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
154 
155  if (used > user_limit) {
156  cerr << " MM_register::enforce_memory_limit: limit=" << user_limit
157  << ", used=" << used << ". allocation exceeds limit.\n";
158  assert(0); //core dump if debugging
159  exit(1);
160  }
161 }
162 
163 
164 /* ************************************************************ */
165 //ignore memory limit accounting
167  register_new = MM_IGNORE_MEMORY_EXCEEDED;
168 }
169 
170 
171 /* ************************************************************ */
172 // provide accounting state
174  return register_new;
175 }
176 
177 /* ************************************************************ */
178 // provide print ccounting state
180  cout << "Memory manager registering memory in ";
181  switch (register_new) {
183  cout << "MM_ABORT_ON_MEMORY_EXCEEDED";
184  break;
186  cout << "MM_WARN_ON_MEMORY_EXCEEDED";
187  break;
189  cout << "MM_IGNORE_MEMORY_EXCEEDED";
190  break;
191  }
192  cout << " mode." << endl;
193 }
194 
195 
196 
197 /* ************************************************************ */
198 //return the amount of memory available before user-specified memory
199 //limit will be exceeded
201  return remaining;
202 }
203 
204 /* ************************************************************ */
206  return used;
207 }
208 
209 
210 /* ************************************************************ */
212  return user_limit;
213 }
214 
215 
216 /* ---------------------------------------------------------------------- */
217 // return the overhead on each memory allocation request
218 
219 
220 // SIZE_SPACE is to ensure alignment on quad word boundaries. It may be
221 // possible to check whether a machine needs this at configuration
222 // time or if dword alignment is ok. On the HP 9000, bus errors occur
223 // when loading doubles that are not qword aligned.
224 static const size_t SIZE_SPACE=(sizeof(size_t) > 8 ? sizeof(size_t) : 8);
225 
226 
227 
229  return SIZE_SPACE;
230 }
231 
232 
233 
234 
235 /* ************************************************************ */
236 // check that new allocation request is below user-defined limit.
237 // This should be a private method, only called by operator new.
239 
240  if (request > remaining) {
241  remaining = 0;
242  used += request;
244 
245  } else {
246  used += request;
247  remaining -= request;
248  return MM_ERROR_NO_ERROR;
249  }
250 }
251 
252 
253 
254 /* ************************************************************ */
255 // do the accounting for a memory deallocation request.
256 // This should be a private method, only called by operators
257 // delete and delete [].
259 
260  if (sz > used) {
261  used = 0;
262  remaining = user_limit;
263  return MM_ERROR_UNDERFLOW;
264  } else {
265 
266  used -= sz;
267  if (used < user_limit) {
268  remaining = user_limit - used;
269  } else {
270  assert(remaining == 0);
271  }
272  return MM_ERROR_NO_ERROR;
273  }
274 }
275 
276 
277 
278 /* ************************************************************ */
279 /* these overloaded operators must only be used by this memory manager
280  * risk of invalid free if these operators are defined outside the MM_register class
281  * e.g. GDAL allocating memory with something else than new as defined here
282  * but then using delete as defined here
283  */
284 #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
285 void* MM_register::operator new[] (size_t sz) throw (std::bad_alloc) {
286 #else
287 void* MM_register::operator new[] (size_t sz) {
288 #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
289  void *p;
290 
291  MM_DEBUG cout << "new: sz=" << sz << ", register "
292  << sz+SIZE_SPACE << "B ,";
293 
294  if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
295  //must be MM_ERROR_INSUF_SPACE
296  switch(MM_manager.register_new) {
297 
299  cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. "
300  << "allocating " << sz << "B. "
301  << "limit exceeded by "
303  << endl;
304  assert (0); // core dump if debugging
305  exit (1);
306  break;
307 
309  cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. "
310  << "allocating " << sz << "B. "
311  << " limit exceeded by "
313  << endl;
314  break;
315 
317  break;
318  }
319  }
320 
321  p = malloc(sz + SIZE_SPACE);
322 
323  if (!p) {
324  cerr << "new: out of memory while allocating " << sz << "B" << endl;
325  assert(0);
326  exit (1);
327  }
328 
329  *((size_t *) p) = sz;
330 
331  MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
332 
333  return ((char *) p) + SIZE_SPACE;
334 }
335 
336 
337 
338 /* ************************************************************ */
339 #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
340 void* MM_register::operator new (size_t sz) throw (std::bad_alloc) {
341 #else
342 void* MM_register::operator new (size_t sz) {
343 #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
344  void *p;
345 
346  MM_DEBUG cout << "new: sz=" << sz << ", register "
347  << sz+SIZE_SPACE << "B ,";
348 
349  if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
350  //must be MM_ERROR_INSUF_SPACE
351  switch(MM_manager.register_new) {
352 
354  cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. "
355  << "allocating " << sz << "B. "
356  << "limit exceeded by "
358  << endl;
359  assert (0); // core dump if debugging
360  exit (1);
361  break;
362 
364  cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. "
365  << "allocating " << sz << "B. "
366  << " limit exceeded by "
368  << endl;
369  break;
370 
372  break;
373  }
374  }
375 
376  p = malloc(sz + SIZE_SPACE);
377 
378  if (!p) {
379  cerr << "new: out of memory while allocating " << sz << "B" << endl;
380  assert(0);
381  exit (1);
382  }
383 
384  *((size_t *) p) = sz;
385 
386  MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
387 
388  return ((char *) p) + SIZE_SPACE;
389 }
390 
391 
392 
393 
394 /* ---------------------------------------------------------------------- */
395 #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
396 void MM_register::operator delete (void *ptr) throw() {
397 #else
398 void MM_register::operator delete (void *ptr) noexcept {
399 #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
400  size_t sz;
401  void *p;
402 
403  MM_DEBUG cout << "delete: ptr=" << ptr << ",";
404 
405  if (!ptr) {
406  cerr << "MM warning: operator delete was given a NULL pointer\n";
407  cerr.flush();
408  //this may actually happen: for instance when calling a default
409  //destructor for something that was not allocated with new
410  //e.g. ofstream str(name) ---- ~ofstream() called ==> ptr=NULL
411 
412  //who wrote the above comment? -RW
413  assert(0);
414  //exit(1);
415  return;
416  }
417 
418  assert(ptr);
419 
420  /* causes invalid free if ptr has not been allocated with new as
421  * defined above */
422  p = ((char *)ptr) - SIZE_SPACE; // the base of memory
423  sz = *((size_t *)p);
424 
425  MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate "
426  << sz + SIZE_SPACE << endl;
427 
428  if(MM_manager.register_deallocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
429  //must be MM_ERROR_UNDERFLOW
430  cerr << "delete: MM_manager.register_deallocation failed\n";
431  assert(0);
432  exit(1);
433  }
434 
435  free(p);
436 }
437 
438 
439 
440 
441 /* ---------------------------------------------------------------------- */
442 #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
443 void MM_register::operator delete[] (void *ptr) throw() {
444 #else
445 void MM_register::operator delete[] (void *ptr) noexcept {
446 #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
447  size_t sz;
448  void *p;
449 
450  MM_DEBUG cout << "delete[]: ptr=" << ptr << ",";
451 
452  if (!ptr) {
453  //can this happen? -- it does: see delete above
454  cerr << "MM warning: operator delete [] was given a NULL pointer\n";
455  cerr.flush();
456  //assert(0);
457  //exit(1);
458  return;
459  }
460  assert(ptr);
461 
462  /* causes invalid free if ptr has not been allocated with new as
463  * defined above */
464  p = ((char *)ptr) - SIZE_SPACE; // the base of memory
465  sz = *((size_t *)p);
466 
467  MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate "
468  << sz + SIZE_SPACE << endl;
469 
470  if(MM_manager.register_deallocation (sz + SIZE_SPACE)!= MM_ERROR_NO_ERROR){
471  //must be MM_ERROR_UNDERFLOW
472  cerr << "delete[]: MM_manager.register_deallocation failed\n";
473  assert(0);
474  exit(1);
475  }
476 
477  free(p);
478 }
479 
480 
481 
482 
483 
484 /* ************************************************************ */
485 // Instantiate the actual memory manager, and allocate the
486 // its static data members
488 int MM_register::instances = 0; // Number of instances. (init)
489 // TPIE's "register memory requests" flag
490 MM_mode MM_register::register_new = MM_IGNORE_MEMORY_EXCEEDED;
491 //This causes constructors for static variables to fail
492 //MM_mode MM_register::register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
493 
494 
495 
496 
497 
498 
499 /* ************************************************************ */
500 // The counter of mm_register_init instances. It is implicitly set to 0.
501 unsigned int mm_register_init::count;
502 
503 // The constructor and destructor that ensure that the memory manager is
504 // created exactly once, and destroyed when appropriate.
506  if (count++ == 0) {
508  }
509 }
510 
512  --count;
513 }
void print_limit_mode()
Definition: mm.cpp:179
#define MM_DEFAULT_MM_SIZE
Definition: mm.h:51
MM_mode
Definition: mm.h:55
~MM_register(void)
Definition: mm.cpp:73
void print()
Definition: mm.cpp:86
MM_err register_deallocation(size_t sz)
Definition: mm.cpp:258
int count
void free(void *)
MM_register()
Definition: mm.cpp:56
MM_err register_allocation(size_t sz)
Definition: mm.cpp:238
int space_overhead()
Definition: mm.cpp:228
mm_register_init(void)
Definition: mm.cpp:505
MM_err
Definition: mm.h:63
void * malloc(YYSIZE_T)
#define MM_DEBUG
Definition: mm.cpp:51
MM_mode get_limit_mode()
Definition: mm.cpp:173
#define assert(condition)
Definition: lz4.c:324
MM_err set_memory_limit(size_t sz)
Definition: mm.cpp:103
void enforce_memory_limit()
Definition: mm.cpp:152
size_t memory_used()
Definition: mm.cpp:205
void warn_memory_limit()
Definition: mm.cpp:145
void ignore_memory_limit()
Definition: mm.cpp:166
~mm_register_init(void)
Definition: mm.cpp:511
MM_register MM_manager
Definition: mm.cpp:487
Definition: mm.h:91
size_t memory_limit()
Definition: mm.cpp:211
size_t memory_available()
Definition: mm.cpp:200