Skip to content

Commit

Permalink
Fix MEMPROFILE (JuliaLang#55236)
Browse files Browse the repository at this point in the history
Should fix JuliaLang#46724.

Example output:

```
   8 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
  16 :    1857/ 725307 objects ( 89% old),   709 pages,    29 kB, 11340 kB waste
  24 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
  32 :   55025/ 922866 objects ( 96% old),  1806 pages,  1719 kB, 28841 kB waste
  40 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
  48 :   31668/ 199826 objects ( 97% old),   586 pages,  1484 kB,  9338 kB waste
  56 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
  64 :   32767/ 118320 objects ( 94% old),   464 pages,  2047 kB,  7311 kB waste
  72 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
  80 :   13711/  19584 objects ( 95% old),    96 pages,  1071 kB,  1486 kB waste
  88 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
  96 :    4893/   8500 objects ( 95% old),    50 pages,   458 kB,   781 kB waste
 104 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
 112 :    3513/   6132 objects ( 99% old),    42 pages,   384 kB,   670 kB waste
 120 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
 128 :    3890/   4572 objects ( 90% old),    36 pages,   486 kB,   532 kB waste
 136 :       0/      0 objects (  0% old),     0 pages,     0 kB,     0 kB waste
 144 :     387/  12656 objects ( 94% old),   112 pages,    54 kB,  1789 kB waste
 160 :     553/   1836 objects ( 96% old),    18 pages,    86 kB,   284 kB waste
 176 :     463/   1395 objects ( 99% old),    15 pages,    79 kB,   239 kB waste
 192 :     170/    765 objects ( 96% old),     9 pages,    31 kB,   142 kB waste
 208 :     137/    468 objects ( 82% old),     6 pages,    27 kB,    91 kB waste
 224 :    6180/   6497 objects ( 99% old),    89 pages,  1351 kB,  1423 kB waste
 240 :      93/    544 objects (100% old),     8 pages,    21 kB,   128 kB waste
 256 :     310/    693 objects ( 98% old),    11 pages,    77 kB,   175 kB waste
 272 :     196/    360 objects ( 91% old),     6 pages,    52 kB,    91 kB waste
 288 :     817/   1120 objects ( 92% old),    20 pages,   229 kB,   301 kB waste
 304 :      67/    265 objects (100% old),     5 pages,    19 kB,    80 kB waste
 336 :     133/    480 objects ( 99% old),    10 pages,    43 kB,   159 kB waste
 368 :     238/    572 objects ( 97% old),    13 pages,    85 kB,   205 kB waste
 400 :      91/    360 objects (100% old),     9 pages,    35 kB,   144 kB waste
 448 :     127/    432 objects ( 96% old),    12 pages,    55 kB,   189 kB waste
 496 :     110/    330 objects ( 99% old),    10 pages,    53 kB,   159 kB waste
 544 :     150/    330 objects ( 98% old),    11 pages,    79 kB,   174 kB waste
 576 :      45/    168 objects (100% old),     6 pages,    25 kB,    96 kB waste
 624 :      61/    182 objects (100% old),     7 pages,    37 kB,   112 kB waste
 672 :      49/    144 objects (100% old),     6 pages,    32 kB,    96 kB waste
 736 :      63/    198 objects ( 93% old),     9 pages,    45 kB,   141 kB waste
 816 :      63/    180 objects ( 98% old),     9 pages,    50 kB,   143 kB waste
 896 :      61/    126 objects (100% old),     7 pages,    53 kB,   112 kB waste
1008 :      59/    128 objects ( 89% old),     8 pages,    58 kB,   122 kB waste
1088 :      67/    120 objects ( 91% old),     8 pages,    71 kB,   121 kB waste
1168 :      22/     70 objects (100% old),     5 pages,    25 kB,    80 kB waste
1248 :      23/     78 objects (100% old),     6 pages,    28 kB,    96 kB waste
1360 :      36/     72 objects ( 97% old),     6 pages,    47 kB,    94 kB waste
1488 :      27/     66 objects (100% old),     6 pages,    39 kB,    96 kB waste
1632 :      22/     50 objects (100% old),     5 pages,    35 kB,    80 kB waste
1808 :      18/     54 objects (100% old),     6 pages,    31 kB,    96 kB waste
2032 :      26/     72 objects (100% old),     9 pages,    51 kB,   144 kB waste
772 kB (82% old) in 167 large objects (82% old)
```
  • Loading branch information
d-netto authored and lazarusA committed Aug 17, 2024
1 parent e4e6c59 commit 70f619a
Showing 2 changed files with 102 additions and 77 deletions.
175 changes: 100 additions & 75 deletions src/gc-debug.c
Original file line number Diff line number Diff line change
@@ -917,113 +917,138 @@ void jl_gc_debug_init(void)
// GC summary stats

#ifdef MEMPROFILE
// TODO repair this and possibly merge with `gc_count_pool`
static size_t pool_stats(jl_gc_pool_t *p, size_t *pwaste, size_t *np,
size_t *pnold)

typedef struct _gc_memprofile_stat_t {
size_t nfree; // for pool only
size_t npgs; // for pool only
size_t nused;
size_t nbytes_used;
size_t nused_old;
size_t nbytes_used_old;
} gc_memprofile_stat_t;

void gc_stats_all_pool(void)
{
jl_taggedvalue_t *halfpages = p->newpages;
size_t osize = p->osize;
size_t nused=0, nfree=0, npgs=0, nold=0;

if (halfpages != NULL) {
npgs++;
char *v = gc_page_data(halfpages) + GC_PAGE_OFFSET;
char *lim = (char*)halfpages - 1;
int i = 0;
while (v <= lim) {
if (!gc_marked(((jl_taggedvalue_t*)v)->bits.gc)) {
nfree++;
gc_memprofile_stat_t stat[JL_GC_N_POOLS];
memset(stat, 0, sizeof(stat));
for (int t_i = 0; t_i < gc_n_threads; t_i++) {
jl_ptls_t ptls2 = gc_all_tls_states[t_i];
if (ptls2 == NULL) {
continue;
}
jl_gc_page_stack_t *pgstk = &ptls2->gc_tls.page_metadata_allocd;
jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&pgstk->bottom);
while (pg != NULL) {
assert(gc_alloc_map_is_set(pg->data));
int pool_n = pg->pool_n;
jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[pool_n];
char *data = pg->data;
// compute the start of the data area in this page
jl_taggedvalue_t *v0 = (jl_taggedvalue_t*)(data + GC_PAGE_OFFSET);
// compute the limit of valid data in this page
char *lim = data + GC_PAGE_SZ - pg->osize;
char *lim_newpages = data + GC_PAGE_SZ;
if (gc_page_data((char*)p->newpages - 1) == data) {
lim_newpages = (char*)p->newpages;
}
else {
nused++;
if (((jl_taggedvalue_t*)v)->bits.gc == GC_OLD_MARKED) {
nold++;
char *v = (char*)v0;
gc_memprofile_stat_t *stat_n = &stat[pool_n];
while (v <= lim) {
uint8_t bits = ((jl_taggedvalue_t*)v)->bits.gc;
if (!gc_marked(bits) || (char*)v >= lim_newpages) {
stat_n->nfree++;
}
else {
if (gc_old(bits)) {
assert(bits == GC_OLD_MARKED);
stat_n->nused_old++;
stat_n->nbytes_used_old += pg->osize;
}
else {
stat_n->nused++;
stat_n->nbytes_used += pg->osize;
}
}
v = v + pg->osize;
}
v = v + osize;
i++;
stat_n->npgs++;
pg = pg->next;
}
// only the first page is allocated on
}
*pwaste = npgs * GC_PAGE_SZ - (nused * p->osize);
*np = npgs;
*pnold = nold;
if (npgs != 0) {
jl_safe_printf("%4d : %7lld/%7lld objects (%3lld%% old), %5lld pages, %5lld kB, %5lld kB waste\n",
p->osize,
(long long)nused,
(long long)(nused + nfree),
(long long)(nused ? (nold * 100) / nused : 0),
(long long)npgs,
(long long)((nused * p->osize) / 1024),
(long long)(*pwaste / 1024));
}
return nused*p->osize;
}

void gc_stats_all_pool(void)
{
size_t nb=0, w, tw=0, no=0, tp=0, nold=0, noldbytes=0, np, nol;
for (int i = 0; i < JL_GC_N_POOLS; i++) {
for (int t_i = 0; t_i < gc_n_threads; t_i++) {
jl_ptls_t ptls2 = gc_all_tls_states[t_i];
size_t b = pool_stats(&ptls2->gc_tls.heap.norm_pools[i], &w, &np, &nol);
nb += b;
no += (b / ptls2->gc_tls.heap.norm_pools[i].osize);
tw += w;
tp += np;
nold += nol;
noldbytes += nol * ptls2->gc_tls.heap.norm_pools[i].osize;
}
jl_ptls_t ptls = jl_current_task->ptls;
jl_gc_pool_t *p = &ptls->gc_tls.heap.norm_pools[i];
gc_memprofile_stat_t *s = &stat[i];
jl_safe_printf("%4d : %7lld/%7lld objects (%3lld%% old), %5lld pages, %5lld kB, %5lld kB waste\n",
p->osize,
(long long)(s->nused + s->nused_old),
(long long)(s->nused + s->nused_old + s->nfree),
(long long)((s->nused + s->nused_old) ? (s->nused_old * 100) / (s->nused + s->nused_old) : 0),
(long long)s->npgs,
(long long)(((s->nused + s->nused_old) * p->osize) / 1024),
(long long)((GC_PAGE_SZ * s->npgs - s->nused * p->osize) / 1024));
}
jl_safe_printf("%lld objects (%lld%% old), %lld kB (%lld%% old) total allocated, "
"%lld total fragments (%lld%% overhead), in %lld pages\n",
(long long)no,
(long long)(no ? (nold * 100) / no : 0),
(long long)(nb / 1024),
(long long)(nb ? (noldbytes * 100) / nb : 0),
(long long)tw,
(long long)(nb ? (tw * 100) / nb : 0),
(long long)tp);
}

void gc_stats_big_obj(void)
{
size_t nused=0, nbytes=0, nused_old=0, nbytes_old=0;
gc_memprofile_stat_t stat;
memset(&stat, 0, sizeof(stat));
for (int t_i = 0; t_i < gc_n_threads; t_i++) {
jl_ptls_t ptls2 = gc_all_tls_states[t_i];
if (ptls2 == NULL) {
continue;
}
bigval_t *v = ptls2->gc_tls.heap.young_generation_of_bigvals;
v = v->next; // skip the sentinel
while (v != NULL) {
if (gc_marked(v->bits.gc)) {
nused++;
nbytes += v->sz & ~3;
if (gc_old(v->bits.gc)) {
assert(v->bits.gc == GC_OLD_MARKED);
stat.nused_old++;
stat.nbytes_used_old += v->sz;
}
else {
stat.nused++;
stat.nbytes_used += v->sz;
}
}
v = v->next;
}
v = oldest_generation_of_bigvals;
v = v->next; // skip the sentinel
while (v != NULL) {
if (gc_marked(v->bits.gc)) {
nused_old++;
nbytes_old += v->sz & ~3;
}
assert(v->bits.gc == GC_OLD_MARKED);
stat.nused_old++;
stat.nbytes_used_old += v->sz;
v = v->next;
}

mallocmemory_t *ma = ptls2->gc_tls.heap.mallocarrays;
while (ma != NULL) {
if (gc_marked(jl_astaggedvalue(ma->a)->bits.gc)) {
nused++;
nbytes += jl_genericmemory_nbytes((jl_genericmemory_t*)ma->a);
uint8_t bits =jl_astaggedvalue(ma->a)->bits.gc;
if (gc_marked(bits)) {
jl_genericmemory_t *m = (jl_genericmemory_t*)ma->a;
m = (jl_genericmemory_t*)((uintptr_t)m & ~(uintptr_t)1);
size_t sz = jl_genericmemory_nbytes(m);
if (gc_old(bits)) {
assert(bits == GC_OLD_MARKED);
stat.nused_old++;
stat.nbytes_used_old += sz;
}
else {
stat.nused++;
stat.nbytes_used += sz;
}
}
ma = ma->next;
}
}

jl_safe_printf("%lld kB (%lld%% old) in %lld large objects (%lld%% old)\n",
(long long)((nbytes + nbytes_old) / 1024),
(long long)(nbytes + nbytes_old ? (nbytes_old * 100) / (nbytes + nbytes_old) : 0),
(long long)(nused + nused_old),
(long long)(nused + nused_old ? (nused_old * 100) / (nused + nused_old) : 0));
(long long)((stat.nbytes_used + stat.nbytes_used_old) / 1024),
(long long)(stat.nbytes_used + stat.nbytes_used_old ? (stat.nbytes_used_old * 100) / (stat.nbytes_used + stat.nbytes_used_old) : 0),
(long long)(stat.nused + stat.nused_old),
(long long)(stat.nused + stat.nused_old ? (stat.nused_old * 100) / (stat.nused + stat.nused_old) : 0));
}
#endif //MEMPROFILE

4 changes: 2 additions & 2 deletions src/options.h
Original file line number Diff line number Diff line change
@@ -68,8 +68,8 @@
// GC_FINAL_STATS prints total GC stats at exit
// #define GC_FINAL_STATS

// MEMPROFILE prints pool summary statistics after every GC
//#define MEMPROFILE
// MEMPROFILE prints pool and large objects summary statistics after every GC
// #define MEMPROFILE

// GC_TIME prints time taken by each phase of GC
// #define GC_TIME

0 comments on commit 70f619a

Please sign in to comment.