railsbench.patch 18 KB

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