From 953ee96f7eaf4a41b51a5f79c67ab3b0689b0e6c Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 16 Apr 2016 15:37:35 -0700 Subject: [PATCH] extend wizard-mode '#stats' command Extend #stats beyond just monsters and objects. Have it display memory usage for traps, engravings, light sources, timers, pending shop wall/floor repair, regions, bones tracking, named object types, and dungeon overview. No doubt there are other memory consumers that I've overlooked. --- doc/fixes36.1 | 1 + include/extern.h | 5 + src/cmd.c | 245 +++++++++++++++++++++++++++++++++++++---------- src/dungeon.c | 44 +++++++++ src/engrave.c | 17 ++++ src/light.c | 17 ++++ src/region.c | 45 +++++++-- src/timeout.c | 17 ++++ 8 files changed, 331 insertions(+), 60 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a200273df..c6b5bc7cf 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -294,6 +294,7 @@ REPRODUCIBLE_BUILD is new config.h setting to fetch build date+time from default value for vibrating square symbol changed from yellow '^' to purple '~' allow symbol set values to be specified via char within single quotes add symbols set "plain", same as default except it uses '+' for corner walls +extend wizard-mode '#stats' command Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 679d486e1..3ac113ca8 100644 --- a/include/extern.h +++ b/include/extern.h @@ -594,6 +594,7 @@ E void NDECL(recalc_mapseen); E void FDECL(mapseen_temple, (struct monst *)); E void FDECL(room_discovered, (int)); E void FDECL(recbranch_mapseen, (d_level *, d_level *)); +E void FDECL(overview_stats, (winid, const char *, long *, long *)); E void FDECL(remdun_mapseen, (int)); /* ### eat.c ### */ @@ -680,6 +681,7 @@ E int NDECL(doengrave); E void NDECL(sanitize_engravings); E void FDECL(save_engravings, (int, int)); E void FDECL(rest_engravings, (int)); +E void FDECL(engr_stats, (const char *, char *, long *, long *)); E void FDECL(del_engr, (struct engr *)); E void FDECL(rloc_engr, (struct engr *)); E void FDECL(make_grave, (int, int, const char *)); @@ -984,6 +986,7 @@ E void FDECL(do_light_sources, (char **)); E struct monst *FDECL(find_mid, (unsigned, unsigned)); E void FDECL(save_light_sources, (int, int, int)); E void FDECL(restore_light_sources, (int)); +E void FDECL(light_stats, (const char *, char *, long *, long *)); E void FDECL(relink_light_sources, (BOOLEAN_P)); E void NDECL(light_sources_sanity_check); E void FDECL(obj_move_light_source, (struct obj *, struct obj *)); @@ -1963,6 +1966,7 @@ E NhRegion *FDECL(visible_region_at, (XCHAR_P, XCHAR_P)); E void FDECL(show_region, (NhRegion *, XCHAR_P, XCHAR_P)); E void FDECL(save_regions, (int, int)); E void FDECL(rest_regions, (int, BOOLEAN_P)); +E void FDECL(region_stats, (const char *, char *, long *, long *)); E NhRegion *FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int)); E boolean NDECL(region_danger); E void NDECL(region_safety); @@ -2307,6 +2311,7 @@ E long FDECL(spot_time_left, (XCHAR_P, XCHAR_P, SHORT_P)); E boolean FDECL(obj_is_local, (struct obj *)); E void FDECL(save_timers, (int, int, int)); E void FDECL(restore_timers, (int, int, BOOLEAN_P, long)); +E void FDECL(timer_stats, (const char *, char *, long *, long *)); E void FDECL(relink_timers, (BOOLEAN_P)); E int NDECL(wiz_timeout_queue); E void NDECL(timer_sanity_check); diff --git a/src/cmd.c b/src/cmd.c index cdad09237..033e73cd6 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -149,12 +149,13 @@ STATIC_DCL int FDECL(size_obj, (struct obj *)); STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, - long *, long *)); + BOOLEAN_P, long *, long *)); STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *)); STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, - long *, long *)); -STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *)); + BOOLEAN_P, long *, long *)); +STATIC_DCL void FDECL(contained_stats, (winid, const char *, long *, long *)); +STATIC_DCL void FDECL(misc_stats, (winid, long *, long *)); STATIC_PTR int NDECL(wiz_show_stats); STATIC_DCL boolean FDECL(accept_menu_prefix, (int NDECL((*)))); #ifdef PORT_DEBUG @@ -2905,9 +2906,9 @@ int NDECL((*fn)); return 0; } -static const char template[] = "%-18s %4ld %6ld"; -static const char count_str[] = " count bytes"; -static const char separator[] = "------------------ ----- ------"; +static const char template[] = "%-27s %4ld %6ld"; +static const char stats_hdr[] = " count bytes"; +static const char stats_sep[] = "--------------------------- ----- -------"; STATIC_OVL int size_obj(otmp) @@ -2955,21 +2956,25 @@ boolean recurse; } STATIC_OVL void -obj_chain(win, src, chain, total_count, total_size) +obj_chain(win, src, chain, force, total_count, total_size) winid win; const char *src; struct obj *chain; +boolean force; long *total_count; long *total_size; { char buf[BUFSZ]; - long count = 0, size = 0; + long count = 0L, size = 0L; count_obj(chain, &count, &size, TRUE, FALSE); - *total_count += count; - *total_size += size; - Sprintf(buf, template, src, count, size); - putstr(win, 0, buf); + + if (count || size || force) { + *total_count += count; + *total_size += size; + Sprintf(buf, template, src, count, size); + putstr(win, 0, buf); + } } STATIC_OVL void @@ -2986,14 +2991,17 @@ long *total_size; for (mon = chain; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, TRUE, FALSE); - *total_count += count; - *total_size += size; - Sprintf(buf, template, src, count, size); - putstr(win, 0, buf); + + if (count || size) { + *total_count += count; + *total_size += size; + Sprintf(buf, template, src, count, size); + putstr(win, 0, buf); + } } STATIC_OVL void -contained(win, src, total_count, total_size) +contained_stats(win, src, total_count, total_size) winid win; const char *src; long *total_count; @@ -3014,11 +3022,12 @@ long *total_size; for (mon = migrating_mons; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, FALSE, TRUE); - *total_count += count; - *total_size += size; - - Sprintf(buf, template, src, count, size); - putstr(win, 0, buf); + if (count || size) { + *total_count += count; + *total_size += size; + Sprintf(buf, template, src, count, size); + putstr(win, 0, buf); + } } STATIC_OVL int @@ -3047,10 +3056,11 @@ struct monst *mtmp; } STATIC_OVL void -mon_chain(win, src, chain, total_count, total_size) +mon_chain(win, src, chain, force, total_count, total_size) winid win; const char *src; struct monst *chain; +boolean force; long *total_count; long *total_size; { @@ -3058,14 +3068,121 @@ long *total_size; long count, size; struct monst *mon; - for (count = size = 0, mon = chain; mon; mon = mon->nmon) { + count = size = 0L; + for (mon = chain; mon; mon = mon->nmon) { count++; size += size_monst(mon); } + if (count || size || force) { + *total_count += count; + *total_size += size; + Sprintf(buf, template, src, count, size); + putstr(win, 0, buf); + } +} + +STATIC_OVL void +misc_stats(win, total_count, total_size) +winid win; +long *total_count; +long *total_size; +{ + char buf[BUFSZ], hdrbuf[QBUFSZ]; + long count, size; + int idx; + struct trap *tt; + struct damage *sd; /* shop damage */ + struct cemetery *bi; /* bones info */ + + /* traps and engravings are output unconditionally; + * others only if nonzero + */ + count = size = 0L; + for (tt = ftrap; tt; tt = tt->ntrap) { + ++count; + size += (long) sizeof *tt; + } *total_count += count; *total_size += size; - Sprintf(buf, template, src, count, size); + Sprintf(hdrbuf, "traps, size %ld", (long) sizeof (struct trap)); + Sprintf(buf, template, hdrbuf, count, size); putstr(win, 0, buf); + + count = size = 0L; + engr_stats("engravings, size %ld+text", hdrbuf, &count, &size); + *total_count += count; + *total_size += size; + Sprintf(buf, template, hdrbuf, count, size); + putstr(win, 0, buf); + + count = size = 0L; + light_stats("light sources, size %ld", hdrbuf, &count, &size); + if (count || size) { + *total_count += count; + *total_size += size; + Sprintf(buf, template, hdrbuf, count, size); + putstr(win, 0, buf); + } + + count = size = 0L; + timer_stats("timers, size %ld", hdrbuf, &count, &size); + if (count || size) { + *total_count += count; + *total_size += size; + Sprintf(buf, template, hdrbuf, count, size); + putstr(win, 0, buf); + } + + count = size = 0L; + for (sd = level.damagelist; sd; sd = sd->next) { + ++count; + size += (long) sizeof *sd; + } + if (count || size) { + *total_count += count; + *total_size += size; + Sprintf(hdrbuf, "shop damage, size %ld", + (long) sizeof (struct damage)); + Sprintf(buf, template, hdrbuf, count, size); + putstr(win, 0, buf); + } + + count = size = 0L; + region_stats("regions, size %ld+%ld*rect+N", hdrbuf, &count, &size); + if (count || size) { + *total_count += count; + *total_size += size; + Sprintf(buf, template, hdrbuf, count, size); + putstr(win, 0, buf); + } + + count = size = 0L; + for (bi = level.bonesinfo; bi; bi = bi->next) { + ++count; + size += (long) sizeof *bi; + } + if (count || size) { + *total_count += count; + *total_size += size; + Sprintf(hdrbuf, "bones history, size %ld", + (long) sizeof (struct cemetery)); + Sprintf(buf, template, hdrbuf, count, size); + putstr(win, 0, buf); + } + + count = size = 0L; + for (idx = 0; idx < NUM_OBJECTS; ++idx) + if (objects[idx].oc_uname) { + ++count; + size += (long) (strlen(objects[idx].oc_uname) + 1); + } + if (count || size) { + *total_count += count; + *total_size += size; + Strcpy(hdrbuf, "object type names, text"); + Sprintf(buf, template, hdrbuf, count, size); + putstr(win, 0, buf); + } } /* @@ -3076,45 +3193,73 @@ wiz_show_stats() { char buf[BUFSZ]; winid win; - long total_obj_size = 0, total_obj_count = 0; - long total_mon_size = 0, total_mon_count = 0; + long total_obj_size, total_obj_count, + total_mon_size, total_mon_count, + total_ovr_size, total_ovr_count, + total_misc_size, total_misc_count; win = create_nhwindow(NHW_TEXT); putstr(win, 0, "Current memory statistics:"); - putstr(win, 0, ""); - Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj)); + + total_obj_count = total_obj_size = 0L; + putstr(win, 0, stats_hdr); + Sprintf(buf, " Objects, base size %ld", (long) sizeof (struct obj)); putstr(win, 0, buf); - putstr(win, 0, ""); - putstr(win, 0, count_str); - - obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size); - obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size); - obj_chain(win, "buried", level.buriedobjlist, &total_obj_count, - &total_obj_size); - obj_chain(win, "migrating obj", migrating_objs, &total_obj_count, - &total_obj_size); + obj_chain(win, "invent", invent, TRUE, &total_obj_count, &total_obj_size); + obj_chain(win, "fobj", fobj, TRUE, &total_obj_count, &total_obj_size); + obj_chain(win, "buried", level.buriedobjlist, FALSE, + &total_obj_count, &total_obj_size); + obj_chain(win, "migrating obj", migrating_objs, FALSE, + &total_obj_count, &total_obj_size); + obj_chain(win, "billobjs", billobjs, FALSE, + &total_obj_count, &total_obj_size); mon_invent_chain(win, "minvent", fmon, &total_obj_count, &total_obj_size); mon_invent_chain(win, "migrating minvent", migrating_mons, &total_obj_count, &total_obj_size); - - contained(win, "contained", &total_obj_count, &total_obj_size); - - putstr(win, 0, separator); - Sprintf(buf, template, "Total", total_obj_count, total_obj_size); + contained_stats(win, "contained", &total_obj_count, &total_obj_size); + putstr(win, 0, stats_sep); + Sprintf(buf, template, " Obj total", total_obj_count, total_obj_size); putstr(win, 0, buf); + total_mon_count = total_mon_size = 0L; putstr(win, 0, ""); - putstr(win, 0, ""); - Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst)); + Sprintf(buf, " Monsters, base size %ld", (long) sizeof (struct monst)); putstr(win, 0, buf); + mon_chain(win, "fmon", fmon, TRUE, &total_mon_count, &total_mon_size); + mon_chain(win, "migrating", migrating_mons, FALSE, + &total_mon_count, &total_mon_size); + /* 'mydogs' is only valid during level change or end of game disclosure, + but conceivably we've been called from within debugger at such time */ + if (mydogs) /* monsters accompanying hero */ + mon_chain(win, "mydogs", mydogs, FALSE, + &total_mon_count, &total_mon_size); + putstr(win, 0, stats_sep); + Sprintf(buf, template, " Mon total", total_mon_count, total_mon_size); + putstr(win, 0, buf); + + total_ovr_count = total_ovr_size = 0L; putstr(win, 0, ""); + putstr(win, 0, " Overview"); + overview_stats(win, template, &total_ovr_count, &total_ovr_size); + putstr(win, 0, stats_sep); + Sprintf(buf, template, " Over total", total_ovr_count, total_ovr_size); + putstr(win, 0, buf); - mon_chain(win, "fmon", fmon, &total_mon_count, &total_mon_size); - mon_chain(win, "migrating", migrating_mons, &total_mon_count, - &total_mon_size); + total_misc_count = total_misc_size = 0L; + putstr(win, 0, ""); + putstr(win, 0, " Miscellaneous"); + misc_stats(win, &total_misc_count, &total_misc_size); + putstr(win, 0, stats_sep); + Sprintf(buf, template, " Misc total", total_misc_count, total_misc_size); + putstr(win, 0, buf); - putstr(win, 0, separator); - Sprintf(buf, template, "Total", total_mon_count, total_mon_size); + putstr(win, 0, ""); + putstr(win, 0, stats_sep); + Sprintf(buf, template, " Grand total", + (total_obj_count + total_mon_count + + total_ovr_count + total_misc_count), + (total_obj_size + total_mon_size + + total_ovr_size + total_misc_size)); putstr(win, 0, buf); #if defined(__BORLANDC__) && !defined(_WIN32) diff --git a/src/dungeon.c b/src/dungeon.c index d101651a0..82610573a 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -2119,6 +2119,50 @@ int fd; return load; } +/* to support '#stats' wizard-mode command */ +void +overview_stats(win, statsfmt, total_count, total_size) +winid win; +const char *statsfmt; +long *total_count, *total_size; +{ + char buf[BUFSZ], hdrbuf[QBUFSZ]; + long ocount, osize, bcount, bsize, acount, asize; + struct cemetery *ce; + mapseen *mptr = find_mapseen(&u.uz); + + ocount = bcount = acount = osize = bsize = asize = 0L; + for (mptr = mapseenchn; mptr; mptr = mptr->next) { + ++ocount; + osize += (long) sizeof *mptr; + for (ce = mptr->final_resting_place; ce; ce = ce->next) { + ++bcount; + bsize += (long) sizeof *ce; + } + if (mptr->custom_lth) { + ++acount; + asize += (long) (mptr->custom_lth + 1); + } + } + + Sprintf(hdrbuf, "general, size %ld", (long) sizeof (mapseen)); + Sprintf(buf, statsfmt, hdrbuf, ocount, osize); + putstr(win, 0, buf); + if (bcount) { + Sprintf(hdrbuf, "cemetery, size %ld", + (long) sizeof (struct cemetery)); + Sprintf(buf, statsfmt, hdrbuf, bcount, bsize); + putstr(win, 0, buf); + } + if (acount) { + Sprintf(hdrbuf, "annotations, text"); + Sprintf(buf, statsfmt, hdrbuf, acount, asize); + putstr(win, 0, buf); + } + *total_count += ocount + bcount + acount; + *total_size += osize + bsize + asize; +} + /* Remove all mapseen objects for a particular dnum. * Useful during quest expulsion to remove quest levels. * [No longer deleted, just marked as unreachable. #overview will diff --git a/src/engrave.c b/src/engrave.c index a4a07bd5b..5347d4968 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -1201,6 +1201,23 @@ int fd; } } +/* to support '#stats' wizard-mode command */ +void +engr_stats(hdrfmt, hdrbuf, count, size) +const char *hdrfmt; +char *hdrbuf; +long *count, *size; +{ + struct engr *ep; + + Sprintf(hdrbuf, hdrfmt, (long) sizeof (struct engr)); + *count = *size = 0L; + for (ep = head_engr; ep; ep = ep->nxt_engr) { + ++*count; + *size += (long) sizeof *ep + (long) ep->engr_lth; + } +} + void del_engr(ep) register struct engr *ep; diff --git a/src/light.c b/src/light.c index 469987cb2..446dc390e 100644 --- a/src/light.c +++ b/src/light.c @@ -306,6 +306,23 @@ int fd; } } +/* to support '#stats' wizard-mode command */ +void +light_stats(hdrfmt, hdrbuf, count, size) +const char *hdrfmt; +char *hdrbuf; +long *count, *size; +{ + light_source *ls; + + Sprintf(hdrbuf, hdrfmt, (long) sizeof (light_source)); + *count = *size = 0L; + for (ls = light_base; ls; ls = ls->next) { + ++*count; + *size += (long) sizeof *ls; + } +} + /* Relink all lights that are so marked. */ void relink_light_sources(ghostly) diff --git a/src/region.c b/src/region.c index 6699716c0..240f7270c 100644 --- a/src/region.c +++ b/src/region.c @@ -95,14 +95,13 @@ int nrect; if (nrect > 0) { reg->bounding_box = rects[0]; } else { - reg->bounding_box.lx = 99; - reg->bounding_box.ly = 99; - reg->bounding_box.hx = 0; + reg->bounding_box.lx = COLNO; + reg->bounding_box.ly = ROWNO; + reg->bounding_box.hx = 0; /* 1 */ reg->bounding_box.hy = 0; } reg->nrects = nrect; - reg->rects = - nrect > 0 ? (NhRect *) alloc((sizeof(NhRect)) * nrect) : (NhRect *) 0; + reg->rects = (nrect > 0) ? (NhRect *) alloc(nrect * sizeof (NhRect)) : 0; for (i = 0; i < nrect; i++) { if (rects[i].lx < reg->bounding_box.lx) reg->bounding_box.lx = rects[i].lx; @@ -145,10 +144,10 @@ NhRect *rect; { NhRect *tmp_rect; - tmp_rect = (NhRect *) alloc(sizeof(NhRect) * (reg->nrects + 1)); + tmp_rect = (NhRect *) alloc((reg->nrects + 1) * sizeof (NhRect)); if (reg->nrects > 0) { (void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects, - (sizeof(NhRect) * reg->nrects)); + reg->nrects * sizeof (NhRect)); free((genericptr_t) reg->rects); } tmp_rect[reg->nrects] = *rect; @@ -177,7 +176,7 @@ struct monst *mon; unsigned *tmp_m; if (reg->max_monst <= reg->n_monst) { - tmp_m = (unsigned *) alloc(sizeof(unsigned) + tmp_m = (unsigned *) alloc(sizeof (unsigned) * (reg->max_monst + MONST_INC)); if (reg->max_monst > 0) { for (i = 0; i < reg->max_monst; i++) @@ -297,10 +296,10 @@ NhRegion *reg; if (max_regions <= n_regions) { tmp_reg = regions; regions = - (NhRegion **) alloc(sizeof(NhRegion *) * (max_regions + 10)); + (NhRegion **) alloc((max_regions + 10) * sizeof (NhRegion *)); if (max_regions > 0) { (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg, - max_regions * sizeof(NhRegion *)); + max_regions * sizeof (NhRegion *)); free((genericptr_t) tmp_reg); } max_regions += 10; @@ -763,6 +762,32 @@ boolean ghostly; /* If a bones file restore */ reset_region_mids(regions[i]); } +/* to support '#stats' wizard-mode command */ +void +region_stats(hdrfmt, hdrbuf, count, size) +const char *hdrfmt; +char *hdrbuf; +long *count, *size; +{ + NhRegion *rg; + int i; + + /* other stats formats take one parameter; this takes two */ + Sprintf(hdrbuf, hdrfmt, (long) sizeof (NhRegion), (long) sizeof (NhRect)); + *count = (long) n_regions; /* might be 0 even though max_regions isn't */ + *size = (long) max_regions * (long) sizeof (NhRegion); + for (i = 0; i < n_regions; ++i) { + rg = regions[i]; + *size += (long) rg->nrects * (long) sizeof (NhRect); + if (rg->enter_msg) + *size += (long) (strlen(rg->enter_msg) + 1); + if (rg->leave_msg) + *size += (long) (strlen(rg->leave_msg) + 1); + *size += (long) rg->max_monst * (long) sizeof *rg->monsters; + } + /* ? */ +} + /* update monster IDs for region being loaded from bones; `ghostly' implied */ STATIC_OVL void reset_region_mids(reg) diff --git a/src/timeout.c b/src/timeout.c index cb93622d7..d4192903d 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1998,6 +1998,23 @@ long adjust; /* how much to adjust timeout */ } } +/* to support '#stats' wizard-mode command */ +void +timer_stats(hdrfmt, hdrbuf, count, size) +const char *hdrfmt; +char *hdrbuf; +long *count, *size; +{ + timer_element *te; + + Sprintf(hdrbuf, hdrfmt, (long) sizeof (timer_element)); + *count = *size = 0L; + for (te = timer_base; te; te = te->next) { + ++*count; + *size += (long) sizeof *te; + } +} + /* reset all timers that are marked for reseting */ void relink_timers(ghostly) -- 2.50.1