mm.cpp 14 KB

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