GRASS GIS 7 Programmer's Manual  7.0.4(2016)-r00000
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 /* ************************************************************ */
56 MM_register::MM_register() {
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 /* ************************************************************ */
73 MM_register::~MM_register(void) {
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 /* ************************************************************ */
86 void MM_register::print() {
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
103 MM_err MM_register::set_memory_limit (size_t new_limit) {
104 
105  assert( new_limit > 0);
106  if (used > new_limit) {
107  // return MM_ERROR_EXCESSIVE_ALLOCATION;
108  switch (register_new) {
109  case MM_ABORT_ON_MEMORY_EXCEEDED:
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 
117  case MM_WARN_ON_MEMORY_EXCEEDED:
118  cerr << " MM_register::set_memory_limit to " << new_limit
119  << ", used " << used << ". allocation exceeds new limit.\n";
120  break;
121 
122  case MM_IGNORE_MEMORY_EXCEEDED:
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
145 void MM_register::warn_memory_limit() {
146  register_new = MM_WARN_ON_MEMORY_EXCEEDED;
147 }
148 
149 
150 /* ************************************************************ */
151 //abort if memory limit exceeded
152 void MM_register::enforce_memory_limit() {
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
166 void MM_register::ignore_memory_limit() {
167  register_new = MM_IGNORE_MEMORY_EXCEEDED;
168 }
169 
170 
171 /* ************************************************************ */
172 // provide accounting state
173 MM_mode MM_register::get_limit_mode() {
174  return register_new;
175 }
176 
177 /* ************************************************************ */
178 // provide print ccounting state
179 void MM_register::print_limit_mode() {
180  cout << "Memory manager registering memory in ";
181  switch (register_new) {
182  case MM_ABORT_ON_MEMORY_EXCEEDED:
183  cout << "MM_ABORT_ON_MEMORY_EXCEEDED";
184  break;
185  case MM_WARN_ON_MEMORY_EXCEEDED:
186  cout << "MM_WARN_ON_MEMORY_EXCEEDED";
187  break;
188  case MM_IGNORE_MEMORY_EXCEEDED:
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
200 size_t MM_register::memory_available() {
201  return remaining;
202 }
203 
204 /* ************************************************************ */
205 size_t MM_register::memory_used() {
206  return used;
207 }
208 
209 
210 /* ************************************************************ */
211 size_t MM_register::memory_limit() {
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 
228 int MM_register::space_overhead () {
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.
238 MM_err MM_register::register_allocation(size_t request) {
239 
240  if (request > remaining) {
241  remaining = 0;
242  used += request;
243  return MM_ERROR_INSUFFICIENT_SPACE;
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 [].
258 MM_err MM_register::register_deallocation(size_t sz) {
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 #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
280 void* operator new[] (size_t sz) throw (std::bad_alloc) {
281 #else
282 void* operator new[] (size_t sz) {
283 #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
284  void *p;
285 
286  MM_DEBUG cout << "new: sz=" << sz << ", register "
287  << sz+SIZE_SPACE << "B ,";
288 
289  if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
290  //must be MM_ERROR_INSUF_SPACE
291  switch(MM_manager.register_new) {
292 
293  case MM_ABORT_ON_MEMORY_EXCEEDED:
294  cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. "
295  << "allocating " << sz << "B. "
296  << "limit exceeded by "
297  << MM_manager.memory_used() - MM_manager.memory_limit()<<"B."
298  << endl;
299  assert (0); // core dump if debugging
300  exit (1);
301  break;
302 
303  case MM_WARN_ON_MEMORY_EXCEEDED:
304  cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. "
305  << "allocating " << sz << "B. "
306  << " limit exceeded by "
307  << MM_manager.memory_used() - MM_manager.memory_limit()<<"B."
308  << endl;
309  break;
310 
311  case MM_IGNORE_MEMORY_EXCEEDED:
312  break;
313  }
314  }
315 
316  p = malloc(sz + SIZE_SPACE);
317 
318  if (!p) {
319  cerr << "new: out of memory while allocating " << sz << "B" << endl;
320  assert(0);
321  exit (1);
322  }
323 
324  *((size_t *) p) = sz;
325 
326  MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
327 
328  return ((char *) p) + SIZE_SPACE;
329 }
330 
331 
332 
333 /* ************************************************************ */
334 #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
335 void* operator new (size_t sz) throw (std::bad_alloc) {
336 #else
337 void* operator new (size_t sz) {
338 #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
339  void *p;
340 
341  MM_DEBUG cout << "new: sz=" << sz << ", register "
342  << sz+SIZE_SPACE << "B ,";
343 
344  if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
345  //must be MM_ERROR_INSUF_SPACE
346  switch(MM_manager.register_new) {
347 
348  case MM_ABORT_ON_MEMORY_EXCEEDED:
349  cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. "
350  << "allocating " << sz << "B. "
351  << "limit exceeded by "
352  << MM_manager.memory_used() - MM_manager.memory_limit()<<"B."
353  << endl;
354  assert (0); // core dump if debugging
355  exit (1);
356  break;
357 
358  case MM_WARN_ON_MEMORY_EXCEEDED:
359  cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. "
360  << "allocating " << sz << "B. "
361  << " limit exceeded by "
362  << MM_manager.memory_used() - MM_manager.memory_limit()<<"B."
363  << endl;
364  break;
365 
366  case MM_IGNORE_MEMORY_EXCEEDED:
367  break;
368  }
369  }
370 
371  p = malloc(sz + SIZE_SPACE);
372 
373  if (!p) {
374  cerr << "new: out of memory while allocating " << sz << "B" << endl;
375  assert(0);
376  exit (1);
377  }
378 
379  *((size_t *) p) = sz;
380 
381  MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
382 
383  return ((char *) p) + SIZE_SPACE;
384 }
385 
386 
387 
388 
389 /* ---------------------------------------------------------------------- */
390 #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
391 void operator delete (void *ptr) throw() {
392 #else
393 void operator delete (void *ptr) noexcept {
394 #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
395  size_t sz;
396  void *p;
397 
398  MM_DEBUG cout << "delete: ptr=" << ptr << ",";
399 
400  if (!ptr) {
401  cerr << "MM warning: operator delete was given a NULL pointer\n";
402  cerr.flush();
403  //this may actually happen: for instance when calling a default
404  //destructor for something that was not allocated with new
405  //e.g. ofstream str(name) ---- ~ofstream() called ==> ptr=NULL
406 
407  //who wrote the above comment? -RW
408  assert(0);
409  //exit(1);
410  return;
411  }
412 
413  assert(ptr);
414  p = ((char *)ptr) - SIZE_SPACE; // the base of memory
415  sz = *((size_t *)p);
416 
417  MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate "
418  << sz + SIZE_SPACE << endl;
419 
420  if(MM_manager.register_deallocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
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 
432 
433 /* ---------------------------------------------------------------------- */
434 #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
435 void operator delete[] (void *ptr) throw() {
436 #else
437 void operator delete[] (void *ptr) noexcept {
438 #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
439  size_t sz;
440  void *p;
441 
442  MM_DEBUG cout << "delete[]: ptr=" << ptr << ",";
443 
444  if (!ptr) {
445  //can this hapen? -- it does: see delete above
446  cerr << "MM warning: operator delete [] was given a NULL pointer\n";
447  cerr.flush();
448  //assert(0);
449  //exit(1);
450  return;
451  }
452  assert(ptr);
453  p = ((char *)ptr) - SIZE_SPACE; // the base of memory
454  sz = *((size_t *)p);
455 
456  MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate "
457  << sz + SIZE_SPACE << endl;
458 
459  if(MM_manager.register_deallocation (sz + SIZE_SPACE)!= MM_ERROR_NO_ERROR){
460  //must be MM_ERROR_UNDERFLOW
461  cerr << "delete[]: MM_manager.register_deallocation failed\n";
462  assert(0);
463  exit(1);
464  }
465 
466  free(p);
467 }
468 
469 
470 
471 
472 
473 /* ************************************************************ */
474 // Instantiate the actual memory manager, and allocate the
475 // its static data members
476 MM_register MM_manager;
477 int MM_register::instances = 0; // Number of instances. (init)
478 // TPIE's "register memory requests" flag
479 MM_mode MM_register::register_new = MM_IGNORE_MEMORY_EXCEEDED;
480 //This causes constructors for static variables to fail
481 //MM_mode MM_register::register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
482 
483 
484 
485 
486 
487 
488 /* ************************************************************ */
489 // The counter of mm_register_init instances. It is implicity set to 0.
490 unsigned int mm_register_init::count;
491 
492 // The constructor and destructor that ensure that the memory manager is
493 // created exactly once, and destroyed when appropriate.
494 mm_register_init::mm_register_init(void) {
495  if (count++ == 0) {
496  MM_manager.set_memory_limit(MM_DEFAULT_MM_SIZE);
497  }
498 }
499 
500 mm_register_init::~mm_register_init(void) {
501  --count;
502 }
int count
#define MM_DEBUG
Definition: mm.cpp:51
MM_register MM_manager
Definition: mm.cpp:476