prof_data.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447
  1. #include "jemalloc/internal/jemalloc_preamble.h"
  2. #include "jemalloc/internal/jemalloc_internal_includes.h"
  3. #include "jemalloc/internal/assert.h"
  4. #include "jemalloc/internal/ckh.h"
  5. #include "jemalloc/internal/hash.h"
  6. #include "jemalloc/internal/malloc_io.h"
  7. #include "jemalloc/internal/prof_data.h"
  8. /*
  9. * This file defines and manages the core profiling data structures.
  10. *
  11. * Conceptually, profiling data can be imagined as a table with three columns:
  12. * thread, stack trace, and current allocation size. (When prof_accum is on,
  13. * there's one additional column which is the cumulative allocation size.)
  14. *
  15. * Implementation wise, each thread maintains a hash recording the stack trace
  16. * to allocation size correspondences, which are basically the individual rows
  17. * in the table. In addition, two global "indices" are built to make data
  18. * aggregation efficient (for dumping): bt2gctx and tdatas, which are basically
  19. * the "grouped by stack trace" and "grouped by thread" views of the same table,
  20. * respectively. Note that the allocation size is only aggregated to the two
  21. * indices at dumping time, so as to optimize for performance.
  22. */
  23. /******************************************************************************/
  24. malloc_mutex_t bt2gctx_mtx;
  25. malloc_mutex_t tdatas_mtx;
  26. malloc_mutex_t prof_dump_mtx;
  27. /*
  28. * Table of mutexes that are shared among gctx's. These are leaf locks, so
  29. * there is no problem with using them for more than one gctx at the same time.
  30. * The primary motivation for this sharing though is that gctx's are ephemeral,
  31. * and destroying mutexes causes complications for systems that allocate when
  32. * creating/destroying mutexes.
  33. */
  34. malloc_mutex_t *gctx_locks;
  35. static atomic_u_t cum_gctxs; /* Atomic counter. */
  36. /*
  37. * Table of mutexes that are shared among tdata's. No operations require
  38. * holding multiple tdata locks, so there is no problem with using them for more
  39. * than one tdata at the same time, even though a gctx lock may be acquired
  40. * while holding a tdata lock.
  41. */
  42. malloc_mutex_t *tdata_locks;
  43. /*
  44. * Global hash of (prof_bt_t *)-->(prof_gctx_t *). This is the master data
  45. * structure that knows about all backtraces currently captured.
  46. */
  47. static ckh_t bt2gctx;
  48. /*
  49. * Tree of all extant prof_tdata_t structures, regardless of state,
  50. * {attached,detached,expired}.
  51. */
  52. static prof_tdata_tree_t tdatas;
  53. size_t prof_unbiased_sz[PROF_SC_NSIZES];
  54. size_t prof_shifted_unbiased_cnt[PROF_SC_NSIZES];
  55. /******************************************************************************/
  56. /* Red-black trees. */
  57. static int
  58. prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) {
  59. uint64_t a_thr_uid = a->thr_uid;
  60. uint64_t b_thr_uid = b->thr_uid;
  61. int ret = (a_thr_uid > b_thr_uid) - (a_thr_uid < b_thr_uid);
  62. if (ret == 0) {
  63. uint64_t a_thr_discrim = a->thr_discrim;
  64. uint64_t b_thr_discrim = b->thr_discrim;
  65. ret = (a_thr_discrim > b_thr_discrim) - (a_thr_discrim <
  66. b_thr_discrim);
  67. if (ret == 0) {
  68. uint64_t a_tctx_uid = a->tctx_uid;
  69. uint64_t b_tctx_uid = b->tctx_uid;
  70. ret = (a_tctx_uid > b_tctx_uid) - (a_tctx_uid <
  71. b_tctx_uid);
  72. }
  73. }
  74. return ret;
  75. }
  76. rb_gen(static UNUSED, tctx_tree_, prof_tctx_tree_t, prof_tctx_t,
  77. tctx_link, prof_tctx_comp)
  78. static int
  79. prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) {
  80. unsigned a_len = a->bt.len;
  81. unsigned b_len = b->bt.len;
  82. unsigned comp_len = (a_len < b_len) ? a_len : b_len;
  83. int ret = memcmp(a->bt.vec, b->bt.vec, comp_len * sizeof(void *));
  84. if (ret == 0) {
  85. ret = (a_len > b_len) - (a_len < b_len);
  86. }
  87. return ret;
  88. }
  89. rb_gen(static UNUSED, gctx_tree_, prof_gctx_tree_t, prof_gctx_t, dump_link,
  90. prof_gctx_comp)
  91. static int
  92. prof_tdata_comp(const prof_tdata_t *a, const prof_tdata_t *b) {
  93. int ret;
  94. uint64_t a_uid = a->thr_uid;
  95. uint64_t b_uid = b->thr_uid;
  96. ret = ((a_uid > b_uid) - (a_uid < b_uid));
  97. if (ret == 0) {
  98. uint64_t a_discrim = a->thr_discrim;
  99. uint64_t b_discrim = b->thr_discrim;
  100. ret = ((a_discrim > b_discrim) - (a_discrim < b_discrim));
  101. }
  102. return ret;
  103. }
  104. rb_gen(static UNUSED, tdata_tree_, prof_tdata_tree_t, prof_tdata_t, tdata_link,
  105. prof_tdata_comp)
  106. /******************************************************************************/
  107. static malloc_mutex_t *
  108. prof_gctx_mutex_choose(void) {
  109. unsigned ngctxs = atomic_fetch_add_u(&cum_gctxs, 1, ATOMIC_RELAXED);
  110. return &gctx_locks[(ngctxs - 1) % PROF_NCTX_LOCKS];
  111. }
  112. static malloc_mutex_t *
  113. prof_tdata_mutex_choose(uint64_t thr_uid) {
  114. return &tdata_locks[thr_uid % PROF_NTDATA_LOCKS];
  115. }
  116. bool
  117. prof_data_init(tsd_t *tsd) {
  118. tdata_tree_new(&tdatas);
  119. return ckh_new(tsd, &bt2gctx, PROF_CKH_MINITEMS,
  120. prof_bt_hash, prof_bt_keycomp);
  121. }
  122. static void
  123. prof_enter(tsd_t *tsd, prof_tdata_t *tdata) {
  124. cassert(config_prof);
  125. assert(tdata == prof_tdata_get(tsd, false));
  126. if (tdata != NULL) {
  127. assert(!tdata->enq);
  128. tdata->enq = true;
  129. }
  130. malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx);
  131. }
  132. static void
  133. prof_leave(tsd_t *tsd, prof_tdata_t *tdata) {
  134. cassert(config_prof);
  135. assert(tdata == prof_tdata_get(tsd, false));
  136. malloc_mutex_unlock(tsd_tsdn(tsd), &bt2gctx_mtx);
  137. if (tdata != NULL) {
  138. bool idump, gdump;
  139. assert(tdata->enq);
  140. tdata->enq = false;
  141. idump = tdata->enq_idump;
  142. tdata->enq_idump = false;
  143. gdump = tdata->enq_gdump;
  144. tdata->enq_gdump = false;
  145. if (idump) {
  146. prof_idump(tsd_tsdn(tsd));
  147. }
  148. if (gdump) {
  149. prof_gdump(tsd_tsdn(tsd));
  150. }
  151. }
  152. }
  153. static prof_gctx_t *
  154. prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) {
  155. /*
  156. * Create a single allocation that has space for vec of length bt->len.
  157. */
  158. size_t size = offsetof(prof_gctx_t, vec) + (bt->len * sizeof(void *));
  159. prof_gctx_t *gctx = (prof_gctx_t *)iallocztm(tsdn, size,
  160. sz_size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true),
  161. true);
  162. if (gctx == NULL) {
  163. return NULL;
  164. }
  165. gctx->lock = prof_gctx_mutex_choose();
  166. /*
  167. * Set nlimbo to 1, in order to avoid a race condition with
  168. * prof_tctx_destroy()/prof_gctx_try_destroy().
  169. */
  170. gctx->nlimbo = 1;
  171. tctx_tree_new(&gctx->tctxs);
  172. /* Duplicate bt. */
  173. memcpy(gctx->vec, bt->vec, bt->len * sizeof(void *));
  174. gctx->bt.vec = gctx->vec;
  175. gctx->bt.len = bt->len;
  176. return gctx;
  177. }
  178. static void
  179. prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self,
  180. prof_gctx_t *gctx) {
  181. cassert(config_prof);
  182. /*
  183. * Check that gctx is still unused by any thread cache before destroying
  184. * it. prof_lookup() increments gctx->nlimbo in order to avoid a race
  185. * condition with this function, as does prof_tctx_destroy() in order to
  186. * avoid a race between the main body of prof_tctx_destroy() and entry
  187. * into this function.
  188. */
  189. prof_enter(tsd, tdata_self);
  190. malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock);
  191. assert(gctx->nlimbo != 0);
  192. if (tctx_tree_empty(&gctx->tctxs) && gctx->nlimbo == 1) {
  193. /* Remove gctx from bt2gctx. */
  194. if (ckh_remove(tsd, &bt2gctx, &gctx->bt, NULL, NULL)) {
  195. not_reached();
  196. }
  197. prof_leave(tsd, tdata_self);
  198. /* Destroy gctx. */
  199. malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
  200. idalloctm(tsd_tsdn(tsd), gctx, NULL, NULL, true, true);
  201. } else {
  202. /*
  203. * Compensate for increment in prof_tctx_destroy() or
  204. * prof_lookup().
  205. */
  206. gctx->nlimbo--;
  207. malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
  208. prof_leave(tsd, tdata_self);
  209. }
  210. }
  211. static bool
  212. prof_gctx_should_destroy(prof_gctx_t *gctx) {
  213. if (opt_prof_accum) {
  214. return false;
  215. }
  216. if (!tctx_tree_empty(&gctx->tctxs)) {
  217. return false;
  218. }
  219. if (gctx->nlimbo != 0) {
  220. return false;
  221. }
  222. return true;
  223. }
  224. static bool
  225. prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata,
  226. void **p_btkey, prof_gctx_t **p_gctx, bool *p_new_gctx) {
  227. union {
  228. prof_gctx_t *p;
  229. void *v;
  230. } gctx, tgctx;
  231. union {
  232. prof_bt_t *p;
  233. void *v;
  234. } btkey;
  235. bool new_gctx;
  236. prof_enter(tsd, tdata);
  237. if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) {
  238. /* bt has never been seen before. Insert it. */
  239. prof_leave(tsd, tdata);
  240. tgctx.p = prof_gctx_create(tsd_tsdn(tsd), bt);
  241. if (tgctx.v == NULL) {
  242. return true;
  243. }
  244. prof_enter(tsd, tdata);
  245. if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) {
  246. gctx.p = tgctx.p;
  247. btkey.p = &gctx.p->bt;
  248. if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) {
  249. /* OOM. */
  250. prof_leave(tsd, tdata);
  251. idalloctm(tsd_tsdn(tsd), gctx.v, NULL, NULL,
  252. true, true);
  253. return true;
  254. }
  255. new_gctx = true;
  256. } else {
  257. new_gctx = false;
  258. }
  259. } else {
  260. tgctx.v = NULL;
  261. new_gctx = false;
  262. }
  263. if (!new_gctx) {
  264. /*
  265. * Increment nlimbo, in order to avoid a race condition with
  266. * prof_tctx_destroy()/prof_gctx_try_destroy().
  267. */
  268. malloc_mutex_lock(tsd_tsdn(tsd), gctx.p->lock);
  269. gctx.p->nlimbo++;
  270. malloc_mutex_unlock(tsd_tsdn(tsd), gctx.p->lock);
  271. new_gctx = false;
  272. if (tgctx.v != NULL) {
  273. /* Lost race to insert. */
  274. idalloctm(tsd_tsdn(tsd), tgctx.v, NULL, NULL, true,
  275. true);
  276. }
  277. }
  278. prof_leave(tsd, tdata);
  279. *p_btkey = btkey.v;
  280. *p_gctx = gctx.p;
  281. *p_new_gctx = new_gctx;
  282. return false;
  283. }
  284. prof_tctx_t *
  285. prof_lookup(tsd_t *tsd, prof_bt_t *bt) {
  286. union {
  287. prof_tctx_t *p;
  288. void *v;
  289. } ret;
  290. prof_tdata_t *tdata;
  291. bool not_found;
  292. cassert(config_prof);
  293. tdata = prof_tdata_get(tsd, false);
  294. assert(tdata != NULL);
  295. malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock);
  296. not_found = ckh_search(&tdata->bt2tctx, bt, NULL, &ret.v);
  297. if (!not_found) { /* Note double negative! */
  298. ret.p->prepared = true;
  299. }
  300. malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
  301. if (not_found) {
  302. void *btkey;
  303. prof_gctx_t *gctx;
  304. bool new_gctx, error;
  305. /*
  306. * This thread's cache lacks bt. Look for it in the global
  307. * cache.
  308. */
  309. if (prof_lookup_global(tsd, bt, tdata, &btkey, &gctx,
  310. &new_gctx)) {
  311. return NULL;
  312. }
  313. /* Link a prof_tctx_t into gctx for this thread. */
  314. ret.v = iallocztm(tsd_tsdn(tsd), sizeof(prof_tctx_t),
  315. sz_size2index(sizeof(prof_tctx_t)), false, NULL, true,
  316. arena_ichoose(tsd, NULL), true);
  317. if (ret.p == NULL) {
  318. if (new_gctx) {
  319. prof_gctx_try_destroy(tsd, tdata, gctx);
  320. }
  321. return NULL;
  322. }
  323. ret.p->tdata = tdata;
  324. ret.p->thr_uid = tdata->thr_uid;
  325. ret.p->thr_discrim = tdata->thr_discrim;
  326. ret.p->recent_count = 0;
  327. memset(&ret.p->cnts, 0, sizeof(prof_cnt_t));
  328. ret.p->gctx = gctx;
  329. ret.p->tctx_uid = tdata->tctx_uid_next++;
  330. ret.p->prepared = true;
  331. ret.p->state = prof_tctx_state_initializing;
  332. malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock);
  333. error = ckh_insert(tsd, &tdata->bt2tctx, btkey, ret.v);
  334. malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
  335. if (error) {
  336. if (new_gctx) {
  337. prof_gctx_try_destroy(tsd, tdata, gctx);
  338. }
  339. idalloctm(tsd_tsdn(tsd), ret.v, NULL, NULL, true, true);
  340. return NULL;
  341. }
  342. malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock);
  343. ret.p->state = prof_tctx_state_nominal;
  344. tctx_tree_insert(&gctx->tctxs, ret.p);
  345. gctx->nlimbo--;
  346. malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
  347. }
  348. return ret.p;
  349. }
  350. /* Used in unit tests. */
  351. static prof_tdata_t *
  352. prof_tdata_count_iter(prof_tdata_tree_t *tdatas_ptr, prof_tdata_t *tdata,
  353. void *arg) {
  354. size_t *tdata_count = (size_t *)arg;
  355. (*tdata_count)++;
  356. return NULL;
  357. }
  358. /* Used in unit tests. */
  359. size_t
  360. prof_tdata_count(void) {
  361. size_t tdata_count = 0;
  362. tsdn_t *tsdn;
  363. tsdn = tsdn_fetch();
  364. malloc_mutex_lock(tsdn, &tdatas_mtx);
  365. tdata_tree_iter(&tdatas, NULL, prof_tdata_count_iter,
  366. (void *)&tdata_count);
  367. malloc_mutex_unlock(tsdn, &tdatas_mtx);
  368. return tdata_count;
  369. }
  370. /* Used in unit tests. */
  371. size_t
  372. prof_bt_count(void) {
  373. size_t bt_count;
  374. tsd_t *tsd;
  375. prof_tdata_t *tdata;
  376. tsd = tsd_fetch();
  377. tdata = prof_tdata_get(tsd, false);
  378. if (tdata == NULL) {
  379. return 0;
  380. }
  381. malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx);
  382. bt_count = ckh_count(&bt2gctx);
  383. malloc_mutex_unlock(tsd_tsdn(tsd), &bt2gctx_mtx);
  384. return bt_count;
  385. }
  386. char *
  387. prof_thread_name_alloc(tsd_t *tsd, const char *thread_name) {
  388. char *ret;
  389. size_t size;
  390. if (thread_name == NULL) {
  391. return NULL;
  392. }
  393. size = strlen(thread_name) + 1;
  394. if (size == 1) {
  395. return "";
  396. }
  397. ret = iallocztm(tsd_tsdn(tsd), size, sz_size2index(size), false, NULL,
  398. true, arena_get(TSDN_NULL, 0, true), true);
  399. if (ret == NULL) {
  400. return NULL;
  401. }
  402. memcpy(ret, thread_name, size);
  403. return ret;
  404. }
  405. int
  406. prof_thread_name_set_impl(tsd_t *tsd, const char *thread_name) {
  407. assert(tsd_reentrancy_level_get(tsd) == 0);
  408. prof_tdata_t *tdata;
  409. unsigned i;
  410. char *s;
  411. tdata = prof_tdata_get(tsd, true);
  412. if (tdata == NULL) {
  413. return EAGAIN;
  414. }
  415. /* Validate input. */
  416. if (thread_name == NULL) {
  417. return EFAULT;
  418. }
  419. for (i = 0; thread_name[i] != '\0'; i++) {
  420. char c = thread_name[i];
  421. if (!isgraph(c) && !isblank(c)) {
  422. return EFAULT;
  423. }
  424. }
  425. s = prof_thread_name_alloc(tsd, thread_name);
  426. if (s == NULL) {
  427. return EAGAIN;
  428. }
  429. if (tdata->thread_name != NULL) {
  430. idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, NULL, true,
  431. true);
  432. tdata->thread_name = NULL;
  433. }
  434. if (strlen(s) > 0) {
  435. tdata->thread_name = s;
  436. }
  437. return 0;
  438. }
  439. JEMALLOC_FORMAT_PRINTF(3, 4)
  440. static void
  441. prof_dump_printf(write_cb_t *prof_dump_write, void *cbopaque,
  442. const char *format, ...) {
  443. va_list ap;
  444. char buf[PROF_PRINTF_BUFSIZE];
  445. va_start(ap, format);
  446. malloc_vsnprintf(buf, sizeof(buf), format, ap);
  447. va_end(ap);
  448. prof_dump_write(cbopaque, buf);
  449. }
  450. /*
  451. * Casting a double to a uint64_t may not necessarily be in range; this can be
  452. * UB. I don't think this is practically possible with the cur counters, but
  453. * plausibly could be with the accum counters.
  454. */
  455. #ifdef JEMALLOC_PROF
  456. static uint64_t
  457. prof_double_uint64_cast(double d) {
  458. /*
  459. * Note: UINT64_MAX + 1 is exactly representable as a double on all
  460. * reasonable platforms (certainly those we'll support). Writing this
  461. * as !(a < b) instead of (a >= b) means that we're NaN-safe.
  462. */
  463. double rounded = round(d);
  464. if (!(rounded < (double)UINT64_MAX)) {
  465. return UINT64_MAX;
  466. }
  467. return (uint64_t)rounded;
  468. }
  469. #endif
  470. void prof_unbias_map_init() {
  471. /* See the comment in prof_sample_new_event_wait */
  472. #ifdef JEMALLOC_PROF
  473. for (szind_t i = 0; i < SC_NSIZES; i++) {
  474. double sz = (double)sz_index2size(i);
  475. double rate = (double)(ZU(1) << lg_prof_sample);
  476. double div_val = 1.0 - exp(-sz / rate);
  477. double unbiased_sz = sz / div_val;
  478. /*
  479. * The "true" right value for the unbiased count is
  480. * 1.0/(1 - exp(-sz/rate)). The problem is, we keep the counts
  481. * as integers (for a variety of reasons -- rounding errors
  482. * could trigger asserts, and not all libcs can properly handle
  483. * floating point arithmetic during malloc calls inside libc).
  484. * Rounding to an integer, though, can lead to rounding errors
  485. * of over 30% for sizes close to the sampling rate. So
  486. * instead, we multiply by a constant, dividing the maximum
  487. * possible roundoff error by that constant. To avoid overflow
  488. * in summing up size_t values, the largest safe constant we can
  489. * pick is the size of the smallest allocation.
  490. */
  491. double cnt_shift = (double)(ZU(1) << SC_LG_TINY_MIN);
  492. double shifted_unbiased_cnt = cnt_shift / div_val;
  493. prof_unbiased_sz[i] = (size_t)round(unbiased_sz);
  494. prof_shifted_unbiased_cnt[i] = (size_t)round(
  495. shifted_unbiased_cnt);
  496. }
  497. #else
  498. unreachable();
  499. #endif
  500. }
  501. /*
  502. * The unbiasing story is long. The jeprof unbiasing logic was copied from
  503. * pprof. Both shared an issue: they unbiased using the average size of the
  504. * allocations at a particular stack trace. This can work out OK if allocations
  505. * are mostly of the same size given some stack, but not otherwise. We now
  506. * internally track what the unbiased results ought to be. We can't just report
  507. * them as they are though; they'll still go through the jeprof unbiasing
  508. * process. Instead, we figure out what values we can feed *into* jeprof's
  509. * unbiasing mechanism that will lead to getting the right values out.
  510. *
  511. * It'll unbias count and aggregate size as:
  512. *
  513. * c_out = c_in * 1/(1-exp(-s_in/c_in/R)
  514. * s_out = s_in * 1/(1-exp(-s_in/c_in/R)
  515. *
  516. * We want to solve for the values of c_in and s_in that will
  517. * give the c_out and s_out that we've computed internally.
  518. *
  519. * Let's do a change of variables (both to make the math easier and to make it
  520. * easier to write):
  521. * x = s_in / c_in
  522. * y = s_in
  523. * k = 1/R.
  524. *
  525. * Then
  526. * c_out = y/x * 1/(1-exp(-k*x))
  527. * s_out = y * 1/(1-exp(-k*x))
  528. *
  529. * The first equation gives:
  530. * y = x * c_out * (1-exp(-k*x))
  531. * The second gives:
  532. * y = s_out * (1-exp(-k*x))
  533. * So we have
  534. * x = s_out / c_out.
  535. * And all the other values fall out from that.
  536. *
  537. * This is all a fair bit of work. The thing we get out of it is that we don't
  538. * break backwards compatibility with jeprof (and the various tools that have
  539. * copied its unbiasing logic). Eventually, we anticipate a v3 heap profile
  540. * dump format based on JSON, at which point I think much of this logic can get
  541. * cleaned up (since we'll be taking a compatibility break there anyways).
  542. */
  543. static void
  544. prof_do_unbias(uint64_t c_out_shifted_i, uint64_t s_out_i, uint64_t *r_c_in,
  545. uint64_t *r_s_in) {
  546. #ifdef JEMALLOC_PROF
  547. if (c_out_shifted_i == 0 || s_out_i == 0) {
  548. *r_c_in = 0;
  549. *r_s_in = 0;
  550. return;
  551. }
  552. /*
  553. * See the note in prof_unbias_map_init() to see why we take c_out in a
  554. * shifted form.
  555. */
  556. double c_out = (double)c_out_shifted_i
  557. / (double)(ZU(1) << SC_LG_TINY_MIN);
  558. double s_out = (double)s_out_i;
  559. double R = (double)(ZU(1) << lg_prof_sample);
  560. double x = s_out / c_out;
  561. double y = s_out * (1.0 - exp(-x / R));
  562. double c_in = y / x;
  563. double s_in = y;
  564. *r_c_in = prof_double_uint64_cast(c_in);
  565. *r_s_in = prof_double_uint64_cast(s_in);
  566. #else
  567. unreachable();
  568. #endif
  569. }
  570. static void
  571. prof_dump_print_cnts(write_cb_t *prof_dump_write, void *cbopaque,
  572. const prof_cnt_t *cnts) {
  573. uint64_t curobjs;
  574. uint64_t curbytes;
  575. uint64_t accumobjs;
  576. uint64_t accumbytes;
  577. if (opt_prof_unbias) {
  578. prof_do_unbias(cnts->curobjs_shifted_unbiased,
  579. cnts->curbytes_unbiased, &curobjs, &curbytes);
  580. prof_do_unbias(cnts->accumobjs_shifted_unbiased,
  581. cnts->accumbytes_unbiased, &accumobjs, &accumbytes);
  582. } else {
  583. curobjs = cnts->curobjs;
  584. curbytes = cnts->curbytes;
  585. accumobjs = cnts->accumobjs;
  586. accumbytes = cnts->accumbytes;
  587. }
  588. prof_dump_printf(prof_dump_write, cbopaque,
  589. "%"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]",
  590. curobjs, curbytes, accumobjs, accumbytes);
  591. }
  592. static void
  593. prof_tctx_merge_tdata(tsdn_t *tsdn, prof_tctx_t *tctx, prof_tdata_t *tdata) {
  594. malloc_mutex_assert_owner(tsdn, tctx->tdata->lock);
  595. malloc_mutex_lock(tsdn, tctx->gctx->lock);
  596. switch (tctx->state) {
  597. case prof_tctx_state_initializing:
  598. malloc_mutex_unlock(tsdn, tctx->gctx->lock);
  599. return;
  600. case prof_tctx_state_nominal:
  601. tctx->state = prof_tctx_state_dumping;
  602. malloc_mutex_unlock(tsdn, tctx->gctx->lock);
  603. memcpy(&tctx->dump_cnts, &tctx->cnts, sizeof(prof_cnt_t));
  604. tdata->cnt_summed.curobjs += tctx->dump_cnts.curobjs;
  605. tdata->cnt_summed.curobjs_shifted_unbiased
  606. += tctx->dump_cnts.curobjs_shifted_unbiased;
  607. tdata->cnt_summed.curbytes += tctx->dump_cnts.curbytes;
  608. tdata->cnt_summed.curbytes_unbiased
  609. += tctx->dump_cnts.curbytes_unbiased;
  610. if (opt_prof_accum) {
  611. tdata->cnt_summed.accumobjs +=
  612. tctx->dump_cnts.accumobjs;
  613. tdata->cnt_summed.accumobjs_shifted_unbiased +=
  614. tctx->dump_cnts.accumobjs_shifted_unbiased;
  615. tdata->cnt_summed.accumbytes +=
  616. tctx->dump_cnts.accumbytes;
  617. tdata->cnt_summed.accumbytes_unbiased +=
  618. tctx->dump_cnts.accumbytes_unbiased;
  619. }
  620. break;
  621. case prof_tctx_state_dumping:
  622. case prof_tctx_state_purgatory:
  623. not_reached();
  624. }
  625. }
  626. static void
  627. prof_tctx_merge_gctx(tsdn_t *tsdn, prof_tctx_t *tctx, prof_gctx_t *gctx) {
  628. malloc_mutex_assert_owner(tsdn, gctx->lock);
  629. gctx->cnt_summed.curobjs += tctx->dump_cnts.curobjs;
  630. gctx->cnt_summed.curobjs_shifted_unbiased
  631. += tctx->dump_cnts.curobjs_shifted_unbiased;
  632. gctx->cnt_summed.curbytes += tctx->dump_cnts.curbytes;
  633. gctx->cnt_summed.curbytes_unbiased += tctx->dump_cnts.curbytes_unbiased;
  634. if (opt_prof_accum) {
  635. gctx->cnt_summed.accumobjs += tctx->dump_cnts.accumobjs;
  636. gctx->cnt_summed.accumobjs_shifted_unbiased
  637. += tctx->dump_cnts.accumobjs_shifted_unbiased;
  638. gctx->cnt_summed.accumbytes += tctx->dump_cnts.accumbytes;
  639. gctx->cnt_summed.accumbytes_unbiased
  640. += tctx->dump_cnts.accumbytes_unbiased;
  641. }
  642. }
  643. static prof_tctx_t *
  644. prof_tctx_merge_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) {
  645. tsdn_t *tsdn = (tsdn_t *)arg;
  646. malloc_mutex_assert_owner(tsdn, tctx->gctx->lock);
  647. switch (tctx->state) {
  648. case prof_tctx_state_nominal:
  649. /* New since dumping started; ignore. */
  650. break;
  651. case prof_tctx_state_dumping:
  652. case prof_tctx_state_purgatory:
  653. prof_tctx_merge_gctx(tsdn, tctx, tctx->gctx);
  654. break;
  655. default:
  656. not_reached();
  657. }
  658. return NULL;
  659. }
  660. typedef struct prof_dump_iter_arg_s prof_dump_iter_arg_t;
  661. struct prof_dump_iter_arg_s {
  662. tsdn_t *tsdn;
  663. write_cb_t *prof_dump_write;
  664. void *cbopaque;
  665. };
  666. static prof_tctx_t *
  667. prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) {
  668. prof_dump_iter_arg_t *arg = (prof_dump_iter_arg_t *)opaque;
  669. malloc_mutex_assert_owner(arg->tsdn, tctx->gctx->lock);
  670. switch (tctx->state) {
  671. case prof_tctx_state_initializing:
  672. case prof_tctx_state_nominal:
  673. /* Not captured by this dump. */
  674. break;
  675. case prof_tctx_state_dumping:
  676. case prof_tctx_state_purgatory:
  677. prof_dump_printf(arg->prof_dump_write, arg->cbopaque,
  678. " t%"FMTu64": ", tctx->thr_uid);
  679. prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque,
  680. &tctx->dump_cnts);
  681. arg->prof_dump_write(arg->cbopaque, "\n");
  682. break;
  683. default:
  684. not_reached();
  685. }
  686. return NULL;
  687. }
  688. static prof_tctx_t *
  689. prof_tctx_finish_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) {
  690. tsdn_t *tsdn = (tsdn_t *)arg;
  691. prof_tctx_t *ret;
  692. malloc_mutex_assert_owner(tsdn, tctx->gctx->lock);
  693. switch (tctx->state) {
  694. case prof_tctx_state_nominal:
  695. /* New since dumping started; ignore. */
  696. break;
  697. case prof_tctx_state_dumping:
  698. tctx->state = prof_tctx_state_nominal;
  699. break;
  700. case prof_tctx_state_purgatory:
  701. ret = tctx;
  702. goto label_return;
  703. default:
  704. not_reached();
  705. }
  706. ret = NULL;
  707. label_return:
  708. return ret;
  709. }
  710. static void
  711. prof_dump_gctx_prep(tsdn_t *tsdn, prof_gctx_t *gctx, prof_gctx_tree_t *gctxs) {
  712. cassert(config_prof);
  713. malloc_mutex_lock(tsdn, gctx->lock);
  714. /*
  715. * Increment nlimbo so that gctx won't go away before dump.
  716. * Additionally, link gctx into the dump list so that it is included in
  717. * prof_dump()'s second pass.
  718. */
  719. gctx->nlimbo++;
  720. gctx_tree_insert(gctxs, gctx);
  721. memset(&gctx->cnt_summed, 0, sizeof(prof_cnt_t));
  722. malloc_mutex_unlock(tsdn, gctx->lock);
  723. }
  724. typedef struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg_t;
  725. struct prof_gctx_merge_iter_arg_s {
  726. tsdn_t *tsdn;
  727. size_t *leak_ngctx;
  728. };
  729. static prof_gctx_t *
  730. prof_gctx_merge_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) {
  731. prof_gctx_merge_iter_arg_t *arg = (prof_gctx_merge_iter_arg_t *)opaque;
  732. malloc_mutex_lock(arg->tsdn, gctx->lock);
  733. tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_merge_iter,
  734. (void *)arg->tsdn);
  735. if (gctx->cnt_summed.curobjs != 0) {
  736. (*arg->leak_ngctx)++;
  737. }
  738. malloc_mutex_unlock(arg->tsdn, gctx->lock);
  739. return NULL;
  740. }
  741. static void
  742. prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) {
  743. prof_tdata_t *tdata = prof_tdata_get(tsd, false);
  744. prof_gctx_t *gctx;
  745. /*
  746. * Standard tree iteration won't work here, because as soon as we
  747. * decrement gctx->nlimbo and unlock gctx, another thread can
  748. * concurrently destroy it, which will corrupt the tree. Therefore,
  749. * tear down the tree one node at a time during iteration.
  750. */
  751. while ((gctx = gctx_tree_first(gctxs)) != NULL) {
  752. gctx_tree_remove(gctxs, gctx);
  753. malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock);
  754. {
  755. prof_tctx_t *next;
  756. next = NULL;
  757. do {
  758. prof_tctx_t *to_destroy =
  759. tctx_tree_iter(&gctx->tctxs, next,
  760. prof_tctx_finish_iter,
  761. (void *)tsd_tsdn(tsd));
  762. if (to_destroy != NULL) {
  763. next = tctx_tree_next(&gctx->tctxs,
  764. to_destroy);
  765. tctx_tree_remove(&gctx->tctxs,
  766. to_destroy);
  767. idalloctm(tsd_tsdn(tsd), to_destroy,
  768. NULL, NULL, true, true);
  769. } else {
  770. next = NULL;
  771. }
  772. } while (next != NULL);
  773. }
  774. gctx->nlimbo--;
  775. if (prof_gctx_should_destroy(gctx)) {
  776. gctx->nlimbo++;
  777. malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
  778. prof_gctx_try_destroy(tsd, tdata, gctx);
  779. } else {
  780. malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
  781. }
  782. }
  783. }
  784. typedef struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg_t;
  785. struct prof_tdata_merge_iter_arg_s {
  786. tsdn_t *tsdn;
  787. prof_cnt_t *cnt_all;
  788. };
  789. static prof_tdata_t *
  790. prof_tdata_merge_iter(prof_tdata_tree_t *tdatas_ptr, prof_tdata_t *tdata,
  791. void *opaque) {
  792. prof_tdata_merge_iter_arg_t *arg =
  793. (prof_tdata_merge_iter_arg_t *)opaque;
  794. malloc_mutex_lock(arg->tsdn, tdata->lock);
  795. if (!tdata->expired) {
  796. size_t tabind;
  797. union {
  798. prof_tctx_t *p;
  799. void *v;
  800. } tctx;
  801. tdata->dumping = true;
  802. memset(&tdata->cnt_summed, 0, sizeof(prof_cnt_t));
  803. for (tabind = 0; !ckh_iter(&tdata->bt2tctx, &tabind, NULL,
  804. &tctx.v);) {
  805. prof_tctx_merge_tdata(arg->tsdn, tctx.p, tdata);
  806. }
  807. arg->cnt_all->curobjs += tdata->cnt_summed.curobjs;
  808. arg->cnt_all->curobjs_shifted_unbiased
  809. += tdata->cnt_summed.curobjs_shifted_unbiased;
  810. arg->cnt_all->curbytes += tdata->cnt_summed.curbytes;
  811. arg->cnt_all->curbytes_unbiased
  812. += tdata->cnt_summed.curbytes_unbiased;
  813. if (opt_prof_accum) {
  814. arg->cnt_all->accumobjs += tdata->cnt_summed.accumobjs;
  815. arg->cnt_all->accumobjs_shifted_unbiased
  816. += tdata->cnt_summed.accumobjs_shifted_unbiased;
  817. arg->cnt_all->accumbytes +=
  818. tdata->cnt_summed.accumbytes;
  819. arg->cnt_all->accumbytes_unbiased +=
  820. tdata->cnt_summed.accumbytes_unbiased;
  821. }
  822. } else {
  823. tdata->dumping = false;
  824. }
  825. malloc_mutex_unlock(arg->tsdn, tdata->lock);
  826. return NULL;
  827. }
  828. static prof_tdata_t *
  829. prof_tdata_dump_iter(prof_tdata_tree_t *tdatas_ptr, prof_tdata_t *tdata,
  830. void *opaque) {
  831. if (!tdata->dumping) {
  832. return NULL;
  833. }
  834. prof_dump_iter_arg_t *arg = (prof_dump_iter_arg_t *)opaque;
  835. prof_dump_printf(arg->prof_dump_write, arg->cbopaque, " t%"FMTu64": ",
  836. tdata->thr_uid);
  837. prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque,
  838. &tdata->cnt_summed);
  839. if (tdata->thread_name != NULL) {
  840. arg->prof_dump_write(arg->cbopaque, " ");
  841. arg->prof_dump_write(arg->cbopaque, tdata->thread_name);
  842. }
  843. arg->prof_dump_write(arg->cbopaque, "\n");
  844. return NULL;
  845. }
  846. static void
  847. prof_dump_header(prof_dump_iter_arg_t *arg, const prof_cnt_t *cnt_all) {
  848. prof_dump_printf(arg->prof_dump_write, arg->cbopaque,
  849. "heap_v2/%"FMTu64"\n t*: ", ((uint64_t)1U << lg_prof_sample));
  850. prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque, cnt_all);
  851. arg->prof_dump_write(arg->cbopaque, "\n");
  852. malloc_mutex_lock(arg->tsdn, &tdatas_mtx);
  853. tdata_tree_iter(&tdatas, NULL, prof_tdata_dump_iter, arg);
  854. malloc_mutex_unlock(arg->tsdn, &tdatas_mtx);
  855. }
  856. static void
  857. prof_dump_gctx(prof_dump_iter_arg_t *arg, prof_gctx_t *gctx,
  858. const prof_bt_t *bt, prof_gctx_tree_t *gctxs) {
  859. cassert(config_prof);
  860. malloc_mutex_assert_owner(arg->tsdn, gctx->lock);
  861. /* Avoid dumping such gctx's that have no useful data. */
  862. if ((!opt_prof_accum && gctx->cnt_summed.curobjs == 0) ||
  863. (opt_prof_accum && gctx->cnt_summed.accumobjs == 0)) {
  864. assert(gctx->cnt_summed.curobjs == 0);
  865. assert(gctx->cnt_summed.curbytes == 0);
  866. /*
  867. * These asserts would not be correct -- see the comment on races
  868. * in prof.c
  869. * assert(gctx->cnt_summed.curobjs_unbiased == 0);
  870. * assert(gctx->cnt_summed.curbytes_unbiased == 0);
  871. */
  872. assert(gctx->cnt_summed.accumobjs == 0);
  873. assert(gctx->cnt_summed.accumobjs_shifted_unbiased == 0);
  874. assert(gctx->cnt_summed.accumbytes == 0);
  875. assert(gctx->cnt_summed.accumbytes_unbiased == 0);
  876. return;
  877. }
  878. arg->prof_dump_write(arg->cbopaque, "@");
  879. for (unsigned i = 0; i < bt->len; i++) {
  880. prof_dump_printf(arg->prof_dump_write, arg->cbopaque,
  881. " %#"FMTxPTR, (uintptr_t)bt->vec[i]);
  882. }
  883. arg->prof_dump_write(arg->cbopaque, "\n t*: ");
  884. prof_dump_print_cnts(arg->prof_dump_write, arg->cbopaque,
  885. &gctx->cnt_summed);
  886. arg->prof_dump_write(arg->cbopaque, "\n");
  887. tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_dump_iter, arg);
  888. }
  889. /*
  890. * See prof_sample_new_event_wait() comment for why the body of this function
  891. * is conditionally compiled.
  892. */
  893. static void
  894. prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_ngctx) {
  895. #ifdef JEMALLOC_PROF
  896. /*
  897. * Scaling is equivalent AdjustSamples() in jeprof, but the result may
  898. * differ slightly from what jeprof reports, because here we scale the
  899. * summary values, whereas jeprof scales each context individually and
  900. * reports the sums of the scaled values.
  901. */
  902. if (cnt_all->curbytes != 0) {
  903. double sample_period = (double)((uint64_t)1 << lg_prof_sample);
  904. double ratio = (((double)cnt_all->curbytes) /
  905. (double)cnt_all->curobjs) / sample_period;
  906. double scale_factor = 1.0 / (1.0 - exp(-ratio));
  907. uint64_t curbytes = (uint64_t)round(((double)cnt_all->curbytes)
  908. * scale_factor);
  909. uint64_t curobjs = (uint64_t)round(((double)cnt_all->curobjs) *
  910. scale_factor);
  911. malloc_printf("<jemalloc>: Leak approximation summary: ~%"FMTu64
  912. " byte%s, ~%"FMTu64" object%s, >= %zu context%s\n",
  913. curbytes, (curbytes != 1) ? "s" : "", curobjs, (curobjs !=
  914. 1) ? "s" : "", leak_ngctx, (leak_ngctx != 1) ? "s" : "");
  915. malloc_printf(
  916. "<jemalloc>: Run jeprof on dump output for leak detail\n");
  917. if (opt_prof_leak_error) {
  918. malloc_printf(
  919. "<jemalloc>: Exiting with error code because memory"
  920. " leaks were detected\n");
  921. /*
  922. * Use _exit() with underscore to avoid calling atexit()
  923. * and entering endless cycle.
  924. */
  925. _exit(1);
  926. }
  927. }
  928. #endif
  929. }
  930. static prof_gctx_t *
  931. prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) {
  932. prof_dump_iter_arg_t *arg = (prof_dump_iter_arg_t *)opaque;
  933. malloc_mutex_lock(arg->tsdn, gctx->lock);
  934. prof_dump_gctx(arg, gctx, &gctx->bt, gctxs);
  935. malloc_mutex_unlock(arg->tsdn, gctx->lock);
  936. return NULL;
  937. }
  938. static void
  939. prof_dump_prep(tsd_t *tsd, prof_tdata_t *tdata, prof_cnt_t *cnt_all,
  940. size_t *leak_ngctx, prof_gctx_tree_t *gctxs) {
  941. size_t tabind;
  942. union {
  943. prof_gctx_t *p;
  944. void *v;
  945. } gctx;
  946. prof_enter(tsd, tdata);
  947. /*
  948. * Put gctx's in limbo and clear their counters in preparation for
  949. * summing.
  950. */
  951. gctx_tree_new(gctxs);
  952. for (tabind = 0; !ckh_iter(&bt2gctx, &tabind, NULL, &gctx.v);) {
  953. prof_dump_gctx_prep(tsd_tsdn(tsd), gctx.p, gctxs);
  954. }
  955. /*
  956. * Iterate over tdatas, and for the non-expired ones snapshot their tctx
  957. * stats and merge them into the associated gctx's.
  958. */
  959. memset(cnt_all, 0, sizeof(prof_cnt_t));
  960. prof_tdata_merge_iter_arg_t prof_tdata_merge_iter_arg = {tsd_tsdn(tsd),
  961. cnt_all};
  962. malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
  963. tdata_tree_iter(&tdatas, NULL, prof_tdata_merge_iter,
  964. &prof_tdata_merge_iter_arg);
  965. malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
  966. /* Merge tctx stats into gctx's. */
  967. *leak_ngctx = 0;
  968. prof_gctx_merge_iter_arg_t prof_gctx_merge_iter_arg = {tsd_tsdn(tsd),
  969. leak_ngctx};
  970. gctx_tree_iter(gctxs, NULL, prof_gctx_merge_iter,
  971. &prof_gctx_merge_iter_arg);
  972. prof_leave(tsd, tdata);
  973. }
  974. void
  975. prof_dump_impl(tsd_t *tsd, write_cb_t *prof_dump_write, void *cbopaque,
  976. prof_tdata_t *tdata, bool leakcheck) {
  977. malloc_mutex_assert_owner(tsd_tsdn(tsd), &prof_dump_mtx);
  978. prof_cnt_t cnt_all;
  979. size_t leak_ngctx;
  980. prof_gctx_tree_t gctxs;
  981. prof_dump_prep(tsd, tdata, &cnt_all, &leak_ngctx, &gctxs);
  982. prof_dump_iter_arg_t prof_dump_iter_arg = {tsd_tsdn(tsd),
  983. prof_dump_write, cbopaque};
  984. prof_dump_header(&prof_dump_iter_arg, &cnt_all);
  985. gctx_tree_iter(&gctxs, NULL, prof_gctx_dump_iter, &prof_dump_iter_arg);
  986. prof_gctx_finish(tsd, &gctxs);
  987. if (leakcheck) {
  988. prof_leakcheck(&cnt_all, leak_ngctx);
  989. }
  990. }
  991. /* Used in unit tests. */
  992. void
  993. prof_cnt_all(prof_cnt_t *cnt_all) {
  994. tsd_t *tsd = tsd_fetch();
  995. prof_tdata_t *tdata = prof_tdata_get(tsd, false);
  996. if (tdata == NULL) {
  997. memset(cnt_all, 0, sizeof(prof_cnt_t));
  998. } else {
  999. size_t leak_ngctx;
  1000. prof_gctx_tree_t gctxs;
  1001. prof_dump_prep(tsd, tdata, cnt_all, &leak_ngctx, &gctxs);
  1002. prof_gctx_finish(tsd, &gctxs);
  1003. }
  1004. }
  1005. void
  1006. prof_bt_hash(const void *key, size_t r_hash[2]) {
  1007. prof_bt_t *bt = (prof_bt_t *)key;
  1008. cassert(config_prof);
  1009. hash(bt->vec, bt->len * sizeof(void *), 0x94122f33U, r_hash);
  1010. }
  1011. bool
  1012. prof_bt_keycomp(const void *k1, const void *k2) {
  1013. const prof_bt_t *bt1 = (prof_bt_t *)k1;
  1014. const prof_bt_t *bt2 = (prof_bt_t *)k2;
  1015. cassert(config_prof);
  1016. if (bt1->len != bt2->len) {
  1017. return false;
  1018. }
  1019. return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0);
  1020. }
  1021. prof_tdata_t *
  1022. prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim,
  1023. char *thread_name, bool active) {
  1024. assert(tsd_reentrancy_level_get(tsd) == 0);
  1025. prof_tdata_t *tdata;
  1026. cassert(config_prof);
  1027. /* Initialize an empty cache for this thread. */
  1028. tdata = (prof_tdata_t *)iallocztm(tsd_tsdn(tsd), sizeof(prof_tdata_t),
  1029. sz_size2index(sizeof(prof_tdata_t)), false, NULL, true,
  1030. arena_get(TSDN_NULL, 0, true), true);
  1031. if (tdata == NULL) {
  1032. return NULL;
  1033. }
  1034. tdata->lock = prof_tdata_mutex_choose(thr_uid);
  1035. tdata->thr_uid = thr_uid;
  1036. tdata->thr_discrim = thr_discrim;
  1037. tdata->thread_name = thread_name;
  1038. tdata->attached = true;
  1039. tdata->expired = false;
  1040. tdata->tctx_uid_next = 0;
  1041. if (ckh_new(tsd, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash,
  1042. prof_bt_keycomp)) {
  1043. idalloctm(tsd_tsdn(tsd), tdata, NULL, NULL, true, true);
  1044. return NULL;
  1045. }
  1046. tdata->enq = false;
  1047. tdata->enq_idump = false;
  1048. tdata->enq_gdump = false;
  1049. tdata->dumping = false;
  1050. tdata->active = active;
  1051. malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
  1052. tdata_tree_insert(&tdatas, tdata);
  1053. malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
  1054. return tdata;
  1055. }
  1056. static bool
  1057. prof_tdata_should_destroy_unlocked(prof_tdata_t *tdata, bool even_if_attached) {
  1058. if (tdata->attached && !even_if_attached) {
  1059. return false;
  1060. }
  1061. if (ckh_count(&tdata->bt2tctx) != 0) {
  1062. return false;
  1063. }
  1064. return true;
  1065. }
  1066. static bool
  1067. prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata,
  1068. bool even_if_attached) {
  1069. malloc_mutex_assert_owner(tsdn, tdata->lock);
  1070. return prof_tdata_should_destroy_unlocked(tdata, even_if_attached);
  1071. }
  1072. static void
  1073. prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata,
  1074. bool even_if_attached) {
  1075. malloc_mutex_assert_owner(tsd_tsdn(tsd), &tdatas_mtx);
  1076. malloc_mutex_assert_not_owner(tsd_tsdn(tsd), tdata->lock);
  1077. tdata_tree_remove(&tdatas, tdata);
  1078. assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached));
  1079. if (tdata->thread_name != NULL) {
  1080. idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, NULL, true,
  1081. true);
  1082. }
  1083. ckh_delete(tsd, &tdata->bt2tctx);
  1084. idalloctm(tsd_tsdn(tsd), tdata, NULL, NULL, true, true);
  1085. }
  1086. static void
  1087. prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) {
  1088. malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
  1089. prof_tdata_destroy_locked(tsd, tdata, even_if_attached);
  1090. malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
  1091. }
  1092. void
  1093. prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata) {
  1094. bool destroy_tdata;
  1095. malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock);
  1096. if (tdata->attached) {
  1097. destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata,
  1098. true);
  1099. /*
  1100. * Only detach if !destroy_tdata, because detaching would allow
  1101. * another thread to win the race to destroy tdata.
  1102. */
  1103. if (!destroy_tdata) {
  1104. tdata->attached = false;
  1105. }
  1106. tsd_prof_tdata_set(tsd, NULL);
  1107. } else {
  1108. destroy_tdata = false;
  1109. }
  1110. malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
  1111. if (destroy_tdata) {
  1112. prof_tdata_destroy(tsd, tdata, true);
  1113. }
  1114. }
  1115. static bool
  1116. prof_tdata_expire(tsdn_t *tsdn, prof_tdata_t *tdata) {
  1117. bool destroy_tdata;
  1118. malloc_mutex_lock(tsdn, tdata->lock);
  1119. if (!tdata->expired) {
  1120. tdata->expired = true;
  1121. destroy_tdata = prof_tdata_should_destroy(tsdn, tdata, false);
  1122. } else {
  1123. destroy_tdata = false;
  1124. }
  1125. malloc_mutex_unlock(tsdn, tdata->lock);
  1126. return destroy_tdata;
  1127. }
  1128. static prof_tdata_t *
  1129. prof_tdata_reset_iter(prof_tdata_tree_t *tdatas_ptr, prof_tdata_t *tdata,
  1130. void *arg) {
  1131. tsdn_t *tsdn = (tsdn_t *)arg;
  1132. return (prof_tdata_expire(tsdn, tdata) ? tdata : NULL);
  1133. }
  1134. void
  1135. prof_reset(tsd_t *tsd, size_t lg_sample) {
  1136. prof_tdata_t *next;
  1137. assert(lg_sample < (sizeof(uint64_t) << 3));
  1138. malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx);
  1139. malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx);
  1140. lg_prof_sample = lg_sample;
  1141. prof_unbias_map_init();
  1142. next = NULL;
  1143. do {
  1144. prof_tdata_t *to_destroy = tdata_tree_iter(&tdatas, next,
  1145. prof_tdata_reset_iter, (void *)tsd);
  1146. if (to_destroy != NULL) {
  1147. next = tdata_tree_next(&tdatas, to_destroy);
  1148. prof_tdata_destroy_locked(tsd, to_destroy, false);
  1149. } else {
  1150. next = NULL;
  1151. }
  1152. } while (next != NULL);
  1153. malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx);
  1154. malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx);
  1155. }
  1156. static bool
  1157. prof_tctx_should_destroy(tsd_t *tsd, prof_tctx_t *tctx) {
  1158. malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
  1159. if (opt_prof_accum) {
  1160. return false;
  1161. }
  1162. if (tctx->cnts.curobjs != 0) {
  1163. return false;
  1164. }
  1165. if (tctx->prepared) {
  1166. return false;
  1167. }
  1168. if (tctx->recent_count != 0) {
  1169. return false;
  1170. }
  1171. return true;
  1172. }
  1173. static void
  1174. prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) {
  1175. malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
  1176. assert(tctx->cnts.curobjs == 0);
  1177. assert(tctx->cnts.curbytes == 0);
  1178. /*
  1179. * These asserts are not correct -- see the comment about races in
  1180. * prof.c
  1181. *
  1182. * assert(tctx->cnts.curobjs_shifted_unbiased == 0);
  1183. * assert(tctx->cnts.curbytes_unbiased == 0);
  1184. */
  1185. assert(!opt_prof_accum);
  1186. assert(tctx->cnts.accumobjs == 0);
  1187. assert(tctx->cnts.accumbytes == 0);
  1188. /*
  1189. * These ones are, since accumbyte counts never go down. Either
  1190. * prof_accum is off (in which case these should never have changed from
  1191. * their initial value of zero), or it's on (in which case we shouldn't
  1192. * be destroying this tctx).
  1193. */
  1194. assert(tctx->cnts.accumobjs_shifted_unbiased == 0);
  1195. assert(tctx->cnts.accumbytes_unbiased == 0);
  1196. prof_gctx_t *gctx = tctx->gctx;
  1197. {
  1198. prof_tdata_t *tdata = tctx->tdata;
  1199. tctx->tdata = NULL;
  1200. ckh_remove(tsd, &tdata->bt2tctx, &gctx->bt, NULL, NULL);
  1201. bool destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd),
  1202. tdata, false);
  1203. malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock);
  1204. if (destroy_tdata) {
  1205. prof_tdata_destroy(tsd, tdata, false);
  1206. }
  1207. }
  1208. bool destroy_tctx, destroy_gctx;
  1209. malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock);
  1210. switch (tctx->state) {
  1211. case prof_tctx_state_nominal:
  1212. tctx_tree_remove(&gctx->tctxs, tctx);
  1213. destroy_tctx = true;
  1214. if (prof_gctx_should_destroy(gctx)) {
  1215. /*
  1216. * Increment gctx->nlimbo in order to keep another
  1217. * thread from winning the race to destroy gctx while
  1218. * this one has gctx->lock dropped. Without this, it
  1219. * would be possible for another thread to:
  1220. *
  1221. * 1) Sample an allocation associated with gctx.
  1222. * 2) Deallocate the sampled object.
  1223. * 3) Successfully prof_gctx_try_destroy(gctx).
  1224. *
  1225. * The result would be that gctx no longer exists by the
  1226. * time this thread accesses it in
  1227. * prof_gctx_try_destroy().
  1228. */
  1229. gctx->nlimbo++;
  1230. destroy_gctx = true;
  1231. } else {
  1232. destroy_gctx = false;
  1233. }
  1234. break;
  1235. case prof_tctx_state_dumping:
  1236. /*
  1237. * A dumping thread needs tctx to remain valid until dumping
  1238. * has finished. Change state such that the dumping thread will
  1239. * complete destruction during a late dump iteration phase.
  1240. */
  1241. tctx->state = prof_tctx_state_purgatory;
  1242. destroy_tctx = false;
  1243. destroy_gctx = false;
  1244. break;
  1245. default:
  1246. not_reached();
  1247. destroy_tctx = false;
  1248. destroy_gctx = false;
  1249. }
  1250. malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock);
  1251. if (destroy_gctx) {
  1252. prof_gctx_try_destroy(tsd, prof_tdata_get(tsd, false), gctx);
  1253. }
  1254. if (destroy_tctx) {
  1255. idalloctm(tsd_tsdn(tsd), tctx, NULL, NULL, true, true);
  1256. }
  1257. }
  1258. void
  1259. prof_tctx_try_destroy(tsd_t *tsd, prof_tctx_t *tctx) {
  1260. malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock);
  1261. if (prof_tctx_should_destroy(tsd, tctx)) {
  1262. /* tctx->tdata->lock will be released in prof_tctx_destroy(). */
  1263. prof_tctx_destroy(tsd, tctx);
  1264. } else {
  1265. malloc_mutex_unlock(tsd_tsdn(tsd), tctx->tdata->lock);
  1266. }
  1267. }
  1268. /******************************************************************************/