c_objsize.c 11 KB

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