ruby187gc.patch 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. --- a/intern.h (revision 31212)
  2. +++ b/intern.h (working copy)
  3. @@ -270,6 +270,15 @@
  4. VALUE rb_gc_enable _((void));
  5. VALUE rb_gc_disable _((void));
  6. VALUE rb_gc_start _((void));
  7. +VALUE rb_gc_enable_stats _((void));
  8. +VALUE rb_gc_disable_stats _((void));
  9. +VALUE rb_gc_allocated_size _((void));
  10. +unsigned long rb_os_live_objects _((void));
  11. +#ifdef HAVE_LONG_LONG
  12. +unsigned long long rb_os_allocated_objects _((void));
  13. +#else
  14. +unsigned long rb_os_allocated_objects _((void));
  15. +#endif
  16. /* hash.c */
  17. void st_foreach_safe _((struct st_table *, int (*)(ANYARGS), unsigned long));
  18. void rb_hash_foreach _((VALUE, int (*)(ANYARGS), VALUE));
  19. --- a/gc.c (revision 31212)
  20. +++ b/gc.c (working copy)
  21. @@ -22,8 +22,16 @@
  22. #include <setjmp.h>
  23. #include <sys/types.h>
  24. +#ifdef _WIN32
  25. +#include <string.h>
  26. +#else
  27. +#include <strings.h>
  28. +#endif
  29. +
  30. #ifdef HAVE_SYS_TIME_H
  31. #include <sys/time.h>
  32. +#elif defined(_WIN32)
  33. +#include <time.h>
  34. #endif
  35. #ifdef HAVE_SYS_RESOURCE_H
  36. @@ -76,6 +84,20 @@
  37. static VALUE nomem_error;
  38. static void garbage_collect();
  39. +static unsigned long live_objects = 0;
  40. +unsigned long rb_os_live_objects()
  41. +{ return live_objects; }
  42. +
  43. +#if defined(HAVE_LONG_LONG)
  44. +static unsigned long long allocated_objects = 0;
  45. +unsigned long long rb_os_allocated_objects()
  46. +{ return allocated_objects; }
  47. +#else
  48. +static unsigned long allocated_objects = 0;
  49. +unsigned long rb_os_allocated_objects()
  50. +{ return allocated_objects; }
  51. +#endif
  52. +
  53. int ruby_gc_stress = 0;
  54. NORETURN(void rb_exc_jump _((VALUE)));
  55. @@ -132,6 +154,10 @@
  56. return bool;
  57. }
  58. +long gc_allocated_size = 0;
  59. +long gc_num_allocations = 0;
  60. +static int gc_statistics = 0;
  61. +
  62. void *
  63. ruby_xmalloc(size)
  64. long size;
  65. @@ -156,6 +182,11 @@
  66. }
  67. malloc_increase += size;
  68. + if (gc_statistics) {
  69. + gc_allocated_size += size;
  70. + gc_num_allocations += 1;
  71. + }
  72. +
  73. return mem;
  74. }
  75. @@ -205,8 +236,16 @@
  76. RUBY_CRITICAL(free(x));
  77. }
  78. +#if HAVE_LONG_LONG
  79. +#define GC_TIME_TYPE LONG_LONG
  80. +#else
  81. +#define GC_TIME_TYPE long
  82. +#endif
  83. +
  84. extern int ruby_in_compile;
  85. static int dont_gc;
  86. +static GC_TIME_TYPE gc_time = 0;
  87. +static int gc_collections = 0;
  88. static int during_gc;
  89. static int need_call_final = 0;
  90. static st_table *finalizer_table = 0;
  91. @@ -255,6 +294,139 @@
  92. return old;
  93. }
  94. +/*
  95. + * call-seq:
  96. + * GC.enable_stats => true or false
  97. + *
  98. + * Enables garbage collection statistics, returning <code>true</code> if garbage
  99. + * collection statistics was already enabled.
  100. + *
  101. + * GC.enable_stats #=> false or true
  102. + * GC.enable_stats #=> true
  103. + *
  104. + */
  105. +
  106. +VALUE
  107. +rb_gc_enable_stats()
  108. +{
  109. + int old = gc_statistics;
  110. + gc_statistics = Qtrue;
  111. + return old;
  112. +}
  113. +
  114. +/*
  115. + * call-seq:
  116. + * GC.disable_stats => true or false
  117. + *
  118. + * Disables garbage collection statistics, returning <code>true</code> if garbage
  119. + * collection statistics was already disabled.
  120. + *
  121. + * GC.disable_stats #=> false or true
  122. + * GC.disable_stats #=> true
  123. + *
  124. + */
  125. +
  126. +VALUE
  127. +rb_gc_disable_stats()
  128. +{
  129. + int old = gc_statistics;
  130. + gc_statistics = Qfalse;
  131. + gc_allocated_size = 0;
  132. + gc_num_allocations = 0;
  133. + return old;
  134. +}
  135. +
  136. +/*
  137. + * call-seq:
  138. + * GC.clear_stats => nil
  139. + *
  140. + * Clears garbage collection statistics, returning nil. This resets the number
  141. + * of collections (GC.collections) and the time used (GC.time) to 0.
  142. + *
  143. + * GC.clear_stats #=> nil
  144. + *
  145. + */
  146. +
  147. +VALUE
  148. +rb_gc_clear_stats()
  149. +{
  150. + gc_collections = 0;
  151. + gc_time = 0;
  152. + gc_allocated_size = 0;
  153. + gc_num_allocations = 0;
  154. + return Qnil;
  155. +}
  156. +
  157. +/*
  158. + * call-seq:
  159. + * GC.allocated_size => Integer
  160. + *
  161. + * Returns the size of memory (in bytes) allocated since GC statistics collection
  162. + * was enabled.
  163. + *
  164. + * GC.allocated_size #=> 35
  165. + *
  166. + */
  167. +VALUE
  168. +rb_gc_allocated_size()
  169. +{
  170. + return INT2NUM(gc_allocated_size);
  171. +}
  172. +
  173. +/*
  174. + * call-seq:
  175. + * GC.num_allocations => Integer
  176. + *
  177. + * Returns the number of memory allocations since GC statistics collection
  178. + * was enabled.
  179. + *
  180. + * GC.num_allocations #=> 150
  181. + *
  182. + */
  183. +VALUE
  184. +rb_gc_num_allocations()
  185. +{
  186. + return INT2NUM(gc_num_allocations);
  187. +}
  188. +
  189. +/*
  190. + * call-seq:
  191. + * GC.collections => Integer
  192. + *
  193. + * Returns the number of garbage collections performed while GC statistics collection
  194. + * was enabled.
  195. + *
  196. + * GC.collections #=> 35
  197. + *
  198. + */
  199. +
  200. +VALUE
  201. +rb_gc_collections()
  202. +{
  203. + return INT2NUM(gc_collections);
  204. +}
  205. +
  206. +/*
  207. + * call-seq:
  208. + * GC.time => Integer
  209. + *
  210. + * Returns the time spent during garbage collection while GC statistics collection
  211. + * was enabled (in micro seconds).
  212. + *
  213. + * GC.time #=> 20000
  214. + *
  215. + */
  216. +
  217. +VALUE
  218. +rb_gc_time()
  219. +{
  220. +#if HAVE_LONG_LONG
  221. + return LL2NUM(gc_time);
  222. +#else
  223. + return LONG2NUM(gc_time);
  224. +#endif
  225. +}
  226. +
  227. VALUE rb_mGC;
  228. static struct gc_list {
  229. @@ -346,7 +518,7 @@
  230. static RVALUE *freelist = 0;
  231. static RVALUE *deferred_final_list = 0;
  232. -#define HEAPS_INCREMENT 10
  233. +static int heaps_increment = 10;
  234. static struct heaps_slot {
  235. void *membase;
  236. RVALUE *slot;
  237. @@ -355,13 +527,164 @@
  238. static int heaps_length = 0;
  239. static int heaps_used = 0;
  240. -#define HEAP_MIN_SLOTS 10000
  241. -static int heap_slots = HEAP_MIN_SLOTS;
  242. +static int heap_min_slots = 10000;
  243. +static int heap_slots = 10000;
  244. -#define FREE_MIN 4096
  245. +static int heap_free_min = 4096;
  246. +static int heap_slots_increment = 10000;
  247. +static double heap_slots_growth_factor = 1.8;
  248. +static long initial_malloc_limit = GC_MALLOC_LIMIT;
  249. +
  250. +static int verbose_gc_stats = Qfalse;
  251. +
  252. +static FILE* gc_data_file = NULL;
  253. +
  254. static RVALUE *himem, *lomem;
  255. +static void set_gc_parameters()
  256. +{
  257. + char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr,
  258. + *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr;
  259. +
  260. + gc_data_file = stderr;
  261. +
  262. + gc_stats_ptr = getenv("RUBY_GC_STATS");
  263. + if (gc_stats_ptr != NULL) {
  264. + int gc_stats_i = atoi(gc_stats_ptr);
  265. + if (gc_stats_i > 0) {
  266. + verbose_gc_stats = Qtrue;
  267. + }
  268. + }
  269. +
  270. + gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE");
  271. + if (gc_heap_file_ptr != NULL) {
  272. + FILE* data_file = fopen(gc_heap_file_ptr, "w");
  273. + if (data_file != NULL) {
  274. + gc_data_file = data_file;
  275. + }
  276. + else {
  277. + fprintf(stderr,
  278. + "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr);
  279. + }
  280. + }
  281. +
  282. + min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
  283. + if (min_slots_ptr != NULL) {
  284. + int min_slots_i = atoi(min_slots_ptr);
  285. + if (verbose_gc_stats) {
  286. + fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr);
  287. + }
  288. + if (min_slots_i > 0) {
  289. + heap_slots = min_slots_i;
  290. + heap_min_slots = min_slots_i;
  291. + }
  292. + }
  293. +
  294. + free_min_ptr = getenv("RUBY_HEAP_FREE_MIN");
  295. + if (free_min_ptr != NULL) {
  296. + int free_min_i = atoi(free_min_ptr);
  297. + if (verbose_gc_stats) {
  298. + fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr);
  299. + }
  300. + if (free_min_i > 0) {
  301. + heap_free_min = free_min_i;
  302. + }
  303. + }
  304. +
  305. + heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT");
  306. + if (heap_incr_ptr != NULL) {
  307. + int heap_incr_i = atoi(heap_incr_ptr);
  308. + if (verbose_gc_stats) {
  309. + fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr);
  310. + }
  311. + if (heap_incr_i > 0) {
  312. + heaps_increment = heap_incr_i;
  313. + }
  314. + }
  315. +
  316. + heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT");
  317. + if (heap_slots_incr_ptr != NULL) {
  318. + int heap_slots_incr_i = atoi(heap_slots_incr_ptr);
  319. + if (verbose_gc_stats) {
  320. + fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr);
  321. + }
  322. + if (heap_slots_incr_i > 0) {
  323. + heap_slots_increment = heap_slots_incr_i;
  324. + }
  325. + }
  326. +
  327. + heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR");
  328. + if (heap_slots_growth_factor_ptr != NULL) {
  329. + double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr);
  330. + if (verbose_gc_stats) {
  331. + fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr);
  332. + }
  333. + if (heap_slots_growth_factor_d > 0) {
  334. + heap_slots_growth_factor = heap_slots_growth_factor_d;
  335. + }
  336. + }
  337. +
  338. + malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
  339. + if (malloc_limit_ptr != NULL) {
  340. + int malloc_limit_i = atol(malloc_limit_ptr);
  341. + if (verbose_gc_stats) {
  342. + fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr);
  343. + }
  344. + if (malloc_limit_i > 0) {
  345. + initial_malloc_limit = malloc_limit_i;
  346. + }
  347. + }
  348. +}
  349. +
  350. +/*
  351. + * call-seq:
  352. + * GC.dump => nil
  353. + *
  354. + * dumps information about the current GC data structures to the GC log file
  355. + *
  356. + * GC.dump #=> nil
  357. + *
  358. + */
  359. +
  360. +VALUE
  361. +rb_gc_dump()
  362. +{
  363. + int i;
  364. +
  365. + for (i = 0; i < heaps_used; i++) {
  366. + int heap_size = heaps[i].limit;
  367. + fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size);
  368. + }
  369. +
  370. + return Qnil;
  371. +}
  372. +
  373. +/*
  374. + * call-seq:
  375. + * GC.log String => String
  376. + *
  377. + * Logs string to the GC data file and returns it.
  378. + *
  379. + * GC.log "manual GC call" #=> "manual GC call"
  380. + *
  381. + */
  382. +
  383. +VALUE
  384. +rb_gc_log(self, original_str)
  385. + VALUE self, original_str;
  386. +{
  387. + if (original_str == Qnil) {
  388. + fprintf(gc_data_file, "\n");
  389. + }
  390. + else {
  391. + VALUE str = StringValue(original_str);
  392. + char *p = RSTRING(str)->ptr;
  393. + fprintf(gc_data_file, "%s\n", p);
  394. + }
  395. + return original_str;
  396. +}
  397. +
  398. static void
  399. add_heap()
  400. {
  401. @@ -372,7 +695,7 @@
  402. struct heaps_slot *p;
  403. int length;
  404. - heaps_length += HEAPS_INCREMENT;
  405. + heaps_length += heaps_increment;
  406. length = heaps_length*sizeof(struct heaps_slot);
  407. RUBY_CRITICAL(
  408. if (heaps_used > 0) {
  409. @@ -388,10 +711,10 @@
  410. for (;;) {
  411. RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
  412. if (p == 0) {
  413. - if (heap_slots == HEAP_MIN_SLOTS) {
  414. + if (heap_slots == heap_min_slots) {
  415. rb_memerror();
  416. }
  417. - heap_slots = HEAP_MIN_SLOTS;
  418. + heap_slots = heap_min_slots;
  419. continue;
  420. }
  421. heaps[heaps_used].membase = p;
  422. @@ -407,8 +730,9 @@
  423. if (lomem == 0 || lomem > p) lomem = p;
  424. if (himem < pend) himem = pend;
  425. heaps_used++;
  426. - heap_slots *= 1.8;
  427. - if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
  428. + heap_slots += heap_slots_increment;
  429. + heap_slots_increment *= heap_slots_growth_factor;
  430. + if (heap_slots <= 0) heap_slots = heap_min_slots;
  431. while (p < pend) {
  432. p->as.free.flags = 0;
  433. @@ -442,6 +766,8 @@
  434. RANY(obj)->file = ruby_sourcefile;
  435. RANY(obj)->line = ruby_sourceline;
  436. #endif
  437. + live_objects++;
  438. + allocated_objects++;
  439. return obj;
  440. }
  441. @@ -1102,6 +1428,39 @@
  442. }
  443. }
  444. +static char* obj_type(int tp)
  445. +{
  446. + switch (tp) {
  447. + case T_NIL : return "NIL";
  448. + case T_OBJECT : return "OBJECT";
  449. + case T_CLASS : return "CLASS";
  450. + case T_ICLASS : return "ICLASS";
  451. + case T_MODULE : return "MODULE";
  452. + case T_FLOAT : return "FLOAT";
  453. + case T_STRING : return "STRING";
  454. + case T_REGEXP : return "REGEXP";
  455. + case T_ARRAY : return "ARRAY";
  456. + case T_FIXNUM : return "FIXNUM";
  457. + case T_HASH : return "HASH";
  458. + case T_STRUCT : return "STRUCT";
  459. + case T_BIGNUM : return "BIGNUM";
  460. + case T_FILE : return "FILE";
  461. +
  462. + case T_TRUE : return "TRUE";
  463. + case T_FALSE : return "FALSE";
  464. + case T_DATA : return "DATA";
  465. + case T_MATCH : return "MATCH";
  466. + case T_SYMBOL : return "SYMBOL";
  467. +
  468. + case T_BLKTAG : return "BLKTAG";
  469. + case T_UNDEF : return "UNDEF";
  470. + case T_VARMAP : return "VARMAP";
  471. + case T_SCOPE : return "SCOPE";
  472. + case T_NODE : return "NODE";
  473. + default: return "____";
  474. + }
  475. +}
  476. +
  477. static void
  478. free_unused_heaps()
  479. {
  480. @@ -1133,14 +1492,24 @@
  481. int i;
  482. unsigned long live = 0;
  483. unsigned long free_min = 0;
  484. + live_objects = 0;
  485. + unsigned long really_freed = 0;
  486. + int free_counts[256];
  487. + int live_counts[256];
  488. + int do_gc_stats = gc_statistics & verbose_gc_stats;
  489. +
  490. for (i = 0; i < heaps_used; i++) {
  491. free_min += heaps[i].limit;
  492. }
  493. free_min = free_min * 0.2;
  494. - if (free_min < FREE_MIN)
  495. - free_min = FREE_MIN;
  496. + if (free_min < heap_free_min)
  497. + free_min = heap_free_min;
  498. + if (do_gc_stats) {
  499. + for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; }
  500. + }
  501. +
  502. if (ruby_in_compile && ruby_parser_stack_on_heap()) {
  503. /* should not reclaim nodes during compilation
  504. if yacc's semantic stack is not allocated on machine stack */
  505. @@ -1171,6 +1540,11 @@
  506. p = heaps[i].slot; pend = p + heaps[i].limit;
  507. while (p < pend) {
  508. if (!(p->as.basic.flags & FL_MARK)) {
  509. + if (p->as.basic.flags) {
  510. + if (do_gc_stats) {
  511. + really_freed++;
  512. + }
  513. + }
  514. if (p->as.basic.flags &&
  515. ((deferred = obj_free((VALUE)p)) ||
  516. ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) {
  517. @@ -1183,6 +1557,12 @@
  518. final_list = p;
  519. }
  520. else {
  521. + if (do_gc_stats) {
  522. + int obt = p->as.basic.flags & T_MASK;
  523. + if (obt) {
  524. + free_counts[obt]++;
  525. + }
  526. + }
  527. add_freelist(p);
  528. }
  529. n++;
  530. @@ -1193,7 +1573,10 @@
  531. }
  532. else {
  533. RBASIC(p)->flags &= ~FL_MARK;
  534. - live++;
  535. + live_objects++;
  536. + if (do_gc_stats) {
  537. + live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++;
  538. + }
  539. }
  540. p++;
  541. }
  542. @@ -1211,8 +1594,8 @@
  543. }
  544. }
  545. if (malloc_increase > malloc_limit) {
  546. - malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
  547. - if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
  548. + malloc_limit += (malloc_increase - malloc_limit) * (double)live_objects / (live_objects + freed);
  549. + if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
  550. }
  551. malloc_increase = 0;
  552. if (freed < free_min) {
  553. @@ -1220,6 +1603,20 @@
  554. }
  555. during_gc = 0;
  556. + if (do_gc_stats) {
  557. + fprintf(gc_data_file, "objects processed: %.7d\n", live+freed);
  558. + fprintf(gc_data_file, "live objects : %.7d\n", live);
  559. + fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed);
  560. + fprintf(gc_data_file, "freed objects : %.7d\n", really_freed);
  561. + for(i=0; i<256; i++) {
  562. + if (free_counts[i]>0) {
  563. + fprintf(gc_data_file,
  564. + "kept %.7d / freed %.7d objects of type %s\n",
  565. + live_counts[i], free_counts[i], obj_type(i));
  566. + }
  567. + }
  568. + }
  569. +
  570. /* clear finalization list */
  571. if (final_list) {
  572. deferred_final_list = final_list;
  573. @@ -1431,6 +1828,7 @@
  574. struct gc_list *list;
  575. struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
  576. jmp_buf save_regs_gc_mark;
  577. + struct timeval gctv1, gctv2;
  578. SET_STACK_END;
  579. #ifdef HAVE_NATIVETHREAD
  580. @@ -1447,6 +1845,14 @@
  581. if (during_gc) return;
  582. during_gc++;
  583. + if (gc_statistics) {
  584. + gc_collections++;
  585. + gettimeofday(&gctv1, NULL);
  586. + if (verbose_gc_stats) {
  587. + fprintf(gc_data_file, "Garbage collection started\n");
  588. + }
  589. + }
  590. +
  591. init_mark_stack();
  592. gc_mark((VALUE)ruby_current_node, 0);
  593. @@ -1522,6 +1928,16 @@
  594. } while (!MARK_STACK_EMPTY);
  595. gc_sweep();
  596. + if (gc_statistics) {
  597. + GC_TIME_TYPE musecs_used;
  598. + gettimeofday(&gctv2, NULL);
  599. + musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec);
  600. + gc_time += musecs_used;
  601. +
  602. + if (verbose_gc_stats) {
  603. + fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000);
  604. + }
  605. + }
  606. }
  607. void
  608. @@ -1703,6 +2119,7 @@
  609. if (!rb_gc_stack_start) {
  610. Init_stack(0);
  611. }
  612. + set_gc_parameters();
  613. add_heap();
  614. }
  615. @@ -2147,6 +2564,33 @@
  616. return (VALUE)((long)obj|FIXNUM_FLAG);
  617. }
  618. +/* call-seq:
  619. + * ObjectSpace.live_objects => number
  620. + *
  621. + * Returns the count of objects currently allocated in the system. This goes
  622. + * down after the garbage collector runs.
  623. + */
  624. +static
  625. +VALUE os_live_objects(VALUE self)
  626. +{ return ULONG2NUM(live_objects); }
  627. +
  628. +/* call-seq:
  629. + * ObjectSpace.allocated_objects => number
  630. + *
  631. + * Returns the count of objects allocated since the Ruby interpreter has
  632. + * started. This number can only increase. To know how many objects are
  633. + * currently allocated, use ObjectSpace::live_objects
  634. + */
  635. +static
  636. +VALUE os_allocated_objects(VALUE self)
  637. +{
  638. +#if defined(HAVE_LONG_LONG)
  639. + return ULL2NUM(allocated_objects);
  640. +#else
  641. + return ULONG2NUM(allocated_objects);
  642. +#endif
  643. +}
  644. +
  645. /*
  646. * The <code>GC</code> module provides an interface to Ruby's mark and
  647. * sweep garbage collection mechanism. Some of the underlying methods
  648. @@ -2166,6 +2610,16 @@
  649. rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1);
  650. rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
  651. + rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0);
  652. + rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0);
  653. + rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0);
  654. + rb_define_singleton_method(rb_mGC, "allocated_size", rb_gc_allocated_size, 0);
  655. + rb_define_singleton_method(rb_mGC, "num_allocations", rb_gc_num_allocations, 0);
  656. + rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0);
  657. + rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0);
  658. + rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0);
  659. + rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1);
  660. +
  661. rb_mObSpace = rb_define_module("ObjectSpace");
  662. rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1);
  663. rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0);
  664. @@ -2173,6 +2627,8 @@
  665. rb_define_module_function(rb_mObSpace, "remove_finalizer", rm_final, 1);
  666. rb_define_module_function(rb_mObSpace, "finalizers", finals, 0);
  667. rb_define_module_function(rb_mObSpace, "call_finalizer", call_final, 1);
  668. + rb_define_module_function(rb_mObSpace, "live_objects", os_live_objects, 0);
  669. + rb_define_module_function(rb_mObSpace, "allocated_objects", os_allocated_objects, 0);
  670. rb_define_module_function(rb_mObSpace, "define_finalizer", define_final, -1);
  671. rb_define_module_function(rb_mObSpace, "undefine_finalizer", undefine_final, 1);