c_objsize.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. #define DBG(x) do { x; fflush(stdout); } while(0)
  3. */
  4. #define DBG(x) do{}while(0)
  5. #define DUMP 0
  6. #define PRF(x) bitarray##x
  7. #include "bitarray.c"
  8. #include "util.h"
  9. #include <caml/memory.h>
  10. // FROM byterun/gc.h
  11. #define Caml_white (0 << 8)
  12. #define Caml_gray (1 << 8)
  13. #define Caml_blue (2 << 8)
  14. #define Caml_black (3 << 8)
  15. #define Colornum_hd(hd) ((color_t) (((hd) >> 8) & 3))
  16. #define Coloredhd_hd(hd,colnum) (((hd) & ~Caml_black) | ((colnum) << 8))
  17. #define Col_white (Caml_white >> 8)
  18. #define Col_gray (Caml_gray >> 8)
  19. #define Col_blue (Caml_blue >> 8)
  20. #define Col_black (Caml_black >> 8)
  21. #define COLORS_INIT_COUNT 256
  22. //--------------------------------------------------------
  23. // From byterun/memory.h:
  24. #define Not_in_heap 0
  25. #define In_heap 1
  26. #define In_young 2
  27. #define In_static_data 4
  28. #define In_code_area 8
  29. #ifdef ARCH_SIXTYFOUR
  30. // 64 bits: Represent page table as a sparse hash table
  31. int caml_page_table_lookup(void * addr);
  32. #define Classify_addr(a) (caml_page_table_lookup((void *)(a)))
  33. #else
  34. // 32 bits: Represent page table as a 2-level array
  35. #define Pagetable2_log 11
  36. #define Pagetable2_size (1 << Pagetable2_log)
  37. #define Pagetable1_log (Page_log + Pagetable2_log)
  38. #define Pagetable1_size (1 << (32 - Pagetable1_log))
  39. CAMLextern unsigned char * caml_page_table[Pagetable1_size];
  40. #define Pagetable_index1(a) (((uintnat)(a)) >> Pagetable1_log)
  41. #define Pagetable_index2(a) \
  42. ((((uintnat)(a)) >> Page_log) & (Pagetable2_size - 1))
  43. #define Classify_addr(a) \
  44. caml_page_table[Pagetable_index1(a)][Pagetable_index2(a)]
  45. #endif
  46. #define Is_in_heap_or_young(a) (Classify_addr(a) & (In_heap | In_young))
  47. //--------------------------------------------------------
  48. unsigned char* colors = NULL;
  49. size_t colors_bitcap = 0;
  50. size_t colors_writeindex = 0;
  51. size_t colors_readindex = 0;
  52. void colors_init(void)
  53. {
  54. ASSERT(colors==NULL, "colors_init");
  55. colors_bitcap = COLORS_INIT_COUNT*2;
  56. colors = bitarray_alloc(colors_bitcap);
  57. colors_writeindex = 0;
  58. colors_readindex = 0;
  59. return;
  60. }
  61. void colors_deinit(void)
  62. {
  63. bitarray_free(colors);
  64. colors = NULL;
  65. return;
  66. }
  67. void writebit(int bit)
  68. {
  69. if (colors_writeindex == colors_bitcap)
  70. {
  71. size_t colors_new_bitcap = colors_bitcap * 2;
  72. unsigned char* newarr = bitarray_realloc(colors, colors_new_bitcap);
  73. ASSERT(newarr != NULL, "realloc");
  74. colors = newarr;
  75. colors_bitcap = colors_new_bitcap;
  76. };
  77. ASSERT(colors_writeindex < colors_bitcap, "bound on write");
  78. bitarray_set(colors, colors_writeindex++, bit);
  79. return;
  80. }
  81. int readbit(void)
  82. {
  83. int res;
  84. ASSERT(colors_readindex < colors_writeindex, "bound on read");
  85. res = bitarray_get(colors, colors_readindex++);
  86. ASSERT(res == 0 || res == 1, "bitarray_get");
  87. return res;
  88. }
  89. void writeint(unsigned int arg, unsigned int width)
  90. {
  91. while(width-- > 0)
  92. {
  93. writebit(arg&1);
  94. arg >>= 1;
  95. };
  96. ASSERT(arg == 0, "writeint");
  97. return;
  98. }
  99. unsigned int readint(unsigned int width)
  100. {
  101. unsigned int acc = 0;
  102. unsigned int hibit = 1 << (width-1);
  103. ASSERT(width > 0, "readint width");
  104. while(width-- > 0)
  105. {
  106. int bit = readbit();
  107. acc >>= 1;
  108. if (bit) acc |= hibit;
  109. };
  110. return acc;
  111. }
  112. int prev_color = 0;
  113. int repeat_count = 0;
  114. #define BITS_FOR_COUNT 5
  115. #define BITS_FOR_ORDER 4
  116. #define MAX_REPEAT_COUNT (1<<BITS_FOR_COUNT)
  117. #define MAX_REPEAT_ORDER (1<<BITS_FOR_ORDER)
  118. void rle_write_repeats(void)
  119. {
  120. while(repeat_count >= MAX_REPEAT_COUNT)
  121. {
  122. unsigned int ord = 0;
  123. while(ord < MAX_REPEAT_ORDER-1 && (1<<ord) <= repeat_count/2)
  124. {
  125. ++ord;
  126. };
  127. writeint(Col_blue, 2);
  128. writeint(1, 1);
  129. ASSERT((1<<ord) != 0, "write_repeats#2");
  130. writeint(ord, BITS_FOR_ORDER);
  131. repeat_count -= (1 << ord);
  132. };
  133. ASSERT(repeat_count < MAX_REPEAT_COUNT, "write_repeats");
  134. if (repeat_count > 0)
  135. {
  136. writeint(Col_blue, 2);
  137. writeint(0, 1);
  138. writeint(repeat_count, BITS_FOR_COUNT);
  139. repeat_count = 0;
  140. };
  141. return;
  142. }
  143. void rle_write_flush(void)
  144. {
  145. if (repeat_count > 0)
  146. {
  147. rle_write_repeats();
  148. };
  149. ASSERT(repeat_count == 0, "rle_write_flush");
  150. return;
  151. }
  152. void rle_read_flush(void)
  153. {
  154. DBG(printf("rle_read_flush: repeat_count=%i, ri=%i, wi=%i\n",
  155. repeat_count, colors_readindex, colors_writeindex)
  156. );
  157. ASSERT
  158. ( repeat_count == 0
  159. && colors_readindex == colors_writeindex
  160. , "rle_reader_flush"
  161. );
  162. return;
  163. }
  164. void rle_write(int color)
  165. {
  166. if (prev_color == color)
  167. {
  168. ++repeat_count;
  169. }
  170. else
  171. {
  172. rle_write_flush();
  173. ASSERT(color != Col_blue, "rle_write");
  174. writeint(color, 2);
  175. prev_color = color;
  176. };
  177. }
  178. int rle_read(void);
  179. int rle_read(void)
  180. {
  181. if (repeat_count > 0)
  182. {
  183. --repeat_count;
  184. return prev_color;
  185. }
  186. else
  187. {
  188. int c = readint(2);
  189. if (c == Col_blue)
  190. {
  191. int rk = readint(1);
  192. if (rk == 0)
  193. { repeat_count = readint(BITS_FOR_COUNT); }
  194. else
  195. { repeat_count = 1 << readint(BITS_FOR_ORDER); };
  196. ASSERT(repeat_count > 0, "rle_read");
  197. return rle_read();
  198. }
  199. else
  200. {
  201. prev_color = c;
  202. return c;
  203. };
  204. };
  205. }
  206. void rle_init(void)
  207. {
  208. prev_color = 0;
  209. repeat_count = 0;
  210. return;
  211. }
  212. void writecolor(int col)
  213. {
  214. ASSERT(col >= 0 && col <= 3 && col != Col_blue, "writecolor");
  215. rle_write(col);
  216. return;
  217. }
  218. int readcolor(void)
  219. {
  220. int res = rle_read();
  221. ASSERT(res >= 0 && res <= 3 && res != Col_blue, "readcolor");
  222. return res;
  223. }
  224. size_t acc_hdrs;
  225. size_t acc_data;
  226. size_t acc_depth;
  227. #define COND_BLOCK(q) \
  228. ( Is_block(q) \
  229. && (Is_in_heap_or_young(q)) \
  230. )
  231. #define GEN_COND_NOTVISITED(v, op) \
  232. ( Colornum_hd(Hd_val(v)) op Col_blue )
  233. #define ENTERING_COND_NOTVISITED(v) GEN_COND_NOTVISITED(v, != )
  234. #define RESTORING_COND_NOTVISITED(v) GEN_COND_NOTVISITED(v, == )
  235. #define REC_WALK(cond_notvisited, rec_call, rec_goto) \
  236. size_t i; \
  237. value prev_block; \
  238. value f; \
  239. prev_block = Val_unit; \
  240. \
  241. for (i=0; i<sz; ++i) \
  242. { \
  243. f = Field(v,i); \
  244. DBG(printf("(*%p)[%i/%i] = %p\n", (void*)v, i, sz, (void*)f)); \
  245. \
  246. if ( COND_BLOCK(f) ) \
  247. { \
  248. if (prev_block != Val_unit && cond_notvisited(prev_block)) \
  249. { \
  250. rec_call \
  251. }; \
  252. prev_block = f; \
  253. }; /* if ( COND_BLOCK ) */ \
  254. }; \
  255. \
  256. if (prev_block != Val_unit && cond_notvisited(prev_block) ) \
  257. { \
  258. rec_goto \
  259. };
  260. void c_rec_objsize(value v, size_t depth)
  261. {
  262. int col;
  263. header_t hd;
  264. size_t sz;
  265. rec_enter:
  266. DBG(printf("c_rec_objsize: v=%p\n"
  267. , (void*)v)
  268. );
  269. sz = Wosize_val(v);
  270. DBG(printf("after_if: v=%p\n", (void*)v));
  271. acc_data += sz;
  272. ++acc_hdrs;
  273. if (depth > acc_depth) { acc_depth = depth; };
  274. hd = Hd_val(v);
  275. col = Colornum_hd(hd);
  276. writecolor(col);
  277. DBG(printf("COL: w %08lx %i\n", v, col));
  278. Hd_val(v) = Coloredhd_hd(hd, Col_blue);
  279. if (Tag_val(v) < No_scan_tag)
  280. {
  281. REC_WALK
  282. ( ENTERING_COND_NOTVISITED
  283. , c_rec_objsize(prev_block, (depth+1));
  284. , v = prev_block; \
  285. depth = depth + 1; \
  286. DBG(printf("goto, depth=%i, v=%p\n", depth, (void*)v)); \
  287. goto rec_enter;
  288. )
  289. }; /* (Tag_val(v) < No_scan_tag) */
  290. return;
  291. }
  292. void restore_colors(value v)
  293. {
  294. int col;
  295. rec_restore:
  296. col = readcolor();
  297. DBG(printf("COL: r %08lx %i\n", v, col));
  298. Hd_val(v) = Coloredhd_hd(Hd_val(v), col);
  299. if (Tag_val(v) < No_scan_tag)
  300. {
  301. size_t sz = Wosize_val(v);
  302. REC_WALK
  303. ( RESTORING_COND_NOTVISITED
  304. , restore_colors(prev_block);
  305. , v = prev_block; \
  306. goto rec_restore;
  307. )
  308. };
  309. return;
  310. }
  311. int c_objsize(value v, value scan, value reach, size_t* headers, size_t* data, size_t* depth)
  312. {
  313. value head;
  314. int reached = 0;
  315. colors_init();
  316. rle_init();
  317. /*
  318. DBG(printf("young heap from %p to %p\n", caml_young_start, caml_young_end));
  319. DBG(printf("old heap from %p to %p\n", caml_heap_start, caml_heap_end));
  320. */
  321. DBG(printf("COL writing\n"));
  322. head = scan;
  323. while( COND_BLOCK(head) ) {
  324. value v = Field(head,0);
  325. header_t hd = Hd_val(v);
  326. int col = Colornum_hd(hd);
  327. head = Field(head,1);
  328. if( col == Col_blue ) continue;
  329. writecolor(col);
  330. Hd_val(v) = Coloredhd_hd(hd, Col_blue);
  331. }
  332. acc_data = 0;
  333. acc_hdrs = 0;
  334. acc_depth = 0;
  335. if ( COND_BLOCK(v) && Colornum_hd(Hd_val(v)) != Col_blue )
  336. {
  337. c_rec_objsize(v, 0);
  338. };
  339. if( headers != NULL ) {
  340. *headers = acc_hdrs;
  341. *data = acc_data;
  342. *depth = acc_depth;
  343. }
  344. rle_write_flush();
  345. DBG(printf("COL reading\n"));
  346. rle_init();
  347. head = scan;
  348. while( COND_BLOCK(head) ) {
  349. value v = Field(head,0);
  350. int col;
  351. head = Field(head,1);
  352. if( Colornum_hd(Hd_val(v)) != Col_blue ) continue;
  353. col = readcolor();
  354. Hd_val(v) = Coloredhd_hd(Hd_val(v), col);
  355. }
  356. while( COND_BLOCK(reach) ) {
  357. value v = Field(reach,0);
  358. if( Colornum_hd(Hd_val(v)) == Col_blue ) {
  359. reached = 1;
  360. break;
  361. }
  362. reach = Field(reach,1);
  363. }
  364. if ( COND_BLOCK(v) && Colornum_hd(Hd_val(v)) == Col_blue )
  365. {
  366. restore_colors(v);
  367. };
  368. rle_read_flush();
  369. #if DUMP
  370. printf("objsize: bytes for rle data = %i\n", colors_readindex/8);
  371. fflush(stdout);
  372. {
  373. FILE* f = fopen("colors-dump", "w");
  374. fwrite(colors, 1, colors_readindex/8, f);
  375. fclose(f);
  376. };
  377. #endif
  378. colors_deinit();
  379. DBG(printf("c_objsize done.\n"));
  380. return reached;
  381. }
  382. #include <caml/alloc.h>
  383. value ml_objsize(value start,value scan,value reach)
  384. {
  385. CAMLparam2(start,scan);
  386. CAMLlocal1(res);
  387. size_t hdrs, data, depth;
  388. int reached = c_objsize(start, scan, reach, &hdrs, &data, &depth);
  389. res = caml_alloc_small(4, 0);
  390. Field(res, 0) = Val_int(data);
  391. Field(res, 1) = Val_int(hdrs);
  392. Field(res, 2) = Val_int(depth);
  393. Field(res, 3) = Val_bool(reached);
  394. CAMLreturn(res);
  395. }