mm.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
  213. void* operator new[] (size_t sz) throw (std::bad_alloc) {
  214. #else
  215. void* operator new[] (size_t sz) {
  216. #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
  217. void *p;
  218. MM_DEBUG cout << "new: sz=" << sz << ", register "
  219. << sz+SIZE_SPACE << "B ,";
  220. if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
  221. //must be MM_ERROR_INSUF_SPACE
  222. switch(MM_manager.register_new) {
  223. case MM_ABORT_ON_MEMORY_EXCEEDED:
  224. cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. "
  225. << "allocating " << sz << "B. "
  226. << "limit exceeded by "
  227. << MM_manager.memory_used() - MM_manager.memory_limit()<<"B."
  228. << endl;
  229. assert (0); // core dump if debugging
  230. exit (1);
  231. break;
  232. case MM_WARN_ON_MEMORY_EXCEEDED:
  233. cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. "
  234. << "allocating " << sz << "B. "
  235. << " limit exceeded by "
  236. << MM_manager.memory_used() - MM_manager.memory_limit()<<"B."
  237. << endl;
  238. break;
  239. case MM_IGNORE_MEMORY_EXCEEDED:
  240. break;
  241. }
  242. }
  243. p = malloc(sz + SIZE_SPACE);
  244. if (!p) {
  245. cerr << "new: out of memory while allocating " << sz << "B" << endl;
  246. assert(0);
  247. exit (1);
  248. }
  249. *((size_t *) p) = sz;
  250. MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
  251. return ((char *) p) + SIZE_SPACE;
  252. }
  253. /* ************************************************************ */
  254. #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
  255. void* operator new (size_t sz) throw (std::bad_alloc) {
  256. #else
  257. void* operator new (size_t sz) {
  258. #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
  259. void *p;
  260. MM_DEBUG cout << "new: sz=" << sz << ", register "
  261. << sz+SIZE_SPACE << "B ,";
  262. if (MM_manager.register_allocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
  263. //must be MM_ERROR_INSUF_SPACE
  264. switch(MM_manager.register_new) {
  265. case MM_ABORT_ON_MEMORY_EXCEEDED:
  266. cerr << "MM error: limit ="<< MM_manager.memory_limit() <<"B. "
  267. << "allocating " << sz << "B. "
  268. << "limit exceeded by "
  269. << MM_manager.memory_used() - MM_manager.memory_limit()<<"B."
  270. << endl;
  271. assert (0); // core dump if debugging
  272. exit (1);
  273. break;
  274. case MM_WARN_ON_MEMORY_EXCEEDED:
  275. cerr << "MM warning: limit="<<MM_manager.memory_limit() <<"B. "
  276. << "allocating " << sz << "B. "
  277. << " limit exceeded by "
  278. << MM_manager.memory_used() - MM_manager.memory_limit()<<"B."
  279. << endl;
  280. break;
  281. case MM_IGNORE_MEMORY_EXCEEDED:
  282. break;
  283. }
  284. }
  285. p = malloc(sz + SIZE_SPACE);
  286. if (!p) {
  287. cerr << "new: out of memory while allocating " << sz << "B" << endl;
  288. assert(0);
  289. exit (1);
  290. }
  291. *((size_t *) p) = sz;
  292. MM_DEBUG cout << "ptr=" << (void*) (((char *) p) + SIZE_SPACE) << endl;
  293. return ((char *) p) + SIZE_SPACE;
  294. }
  295. /* ---------------------------------------------------------------------- */
  296. #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
  297. void operator delete (void *ptr) throw() {
  298. #else
  299. void operator delete (void *ptr) noexcept {
  300. #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
  301. size_t sz;
  302. void *p;
  303. MM_DEBUG cout << "delete: ptr=" << ptr << ",";
  304. if (!ptr) {
  305. cerr << "MM warning: operator delete was given a NULL pointer\n";
  306. cerr.flush();
  307. //this may actually happen: for instance when calling a default
  308. //destructor for something that was not allocated with new
  309. //e.g. ofstream str(name) ---- ~ofstream() called ==> ptr=NULL
  310. //who wrote the above comment? -RW
  311. assert(0);
  312. //exit(1);
  313. return;
  314. }
  315. assert(ptr);
  316. p = ((char *)ptr) - SIZE_SPACE; // the base of memory
  317. sz = *((size_t *)p);
  318. MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate "
  319. << sz + SIZE_SPACE << endl;
  320. if(MM_manager.register_deallocation (sz + SIZE_SPACE) != MM_ERROR_NO_ERROR){
  321. //must be MM_ERROR_UNDERFLOW
  322. cerr << "delete: MM_manager.register_deallocation failed\n";
  323. assert(0);
  324. exit(1);
  325. }
  326. free(p);
  327. }
  328. /* ---------------------------------------------------------------------- */
  329. #ifdef GRASS_MM_USE_EXCEPTION_SPECIFIER
  330. void operator delete[] (void *ptr) throw() {
  331. #else
  332. void operator delete[] (void *ptr) noexcept {
  333. #endif /* GRASS_MM_USE_EXCEPTION_SPECIFIER */
  334. size_t sz;
  335. void *p;
  336. MM_DEBUG cout << "delete[]: ptr=" << ptr << ",";
  337. if (!ptr) {
  338. //can this happen? -- it does: see delete above
  339. cerr << "MM warning: operator delete [] was given a NULL pointer\n";
  340. cerr.flush();
  341. //assert(0);
  342. //exit(1);
  343. return;
  344. }
  345. assert(ptr);
  346. p = ((char *)ptr) - SIZE_SPACE; // the base of memory
  347. sz = *((size_t *)p);
  348. MM_DEBUG cout << "size=" << sz <<", free " << p << "B and deallocate "
  349. << sz + SIZE_SPACE << endl;
  350. if(MM_manager.register_deallocation (sz + SIZE_SPACE)!= MM_ERROR_NO_ERROR){
  351. //must be MM_ERROR_UNDERFLOW
  352. cerr << "delete[]: MM_manager.register_deallocation failed\n";
  353. assert(0);
  354. exit(1);
  355. }
  356. free(p);
  357. }
  358. /* ************************************************************ */
  359. // Instantiate the actual memory manager, and allocate the
  360. // its static data members
  361. MM_register MM_manager;
  362. int MM_register::instances = 0; // Number of instances. (init)
  363. // TPIE's "register memory requests" flag
  364. MM_mode MM_register::register_new = MM_IGNORE_MEMORY_EXCEEDED;
  365. //This causes constructors for static variables to fail
  366. //MM_mode MM_register::register_new = MM_ABORT_ON_MEMORY_EXCEEDED;
  367. /* ************************************************************ */
  368. // The counter of mm_register_init instances. It is implicitly set to 0.
  369. unsigned int mm_register_init::count;
  370. // The constructor and destructor that ensure that the memory manager is
  371. // created exactly once, and destroyed when appropriate.
  372. mm_register_init::mm_register_init(void) {
  373. if (count++ == 0) {
  374. MM_manager.set_memory_limit(MM_DEFAULT_MM_SIZE);
  375. }
  376. }
  377. mm_register_init::~mm_register_init(void) {
  378. --count;
  379. }