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