From 17414c500a444d48bae0ec570acff5dd3371a005 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 25 Jan 2024 23:59:32 -0800 Subject: [PATCH] more monster iteration Re-use the array allocated for iterating over all monsters during monster movement much of the time. It was being allocated from scratch for each round of monster movement, then freed after they moved, then repeated the next round. --- include/extern.h | 1 + src/mon.c | 45 +++++++++++++++++++++++++++++++++++---------- src/save.c | 3 +-- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/include/extern.h b/include/extern.h index f6a2d8982..48a410337 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1736,6 +1736,7 @@ extern void wake_nearby(void); extern void wake_nearto(coordxy, coordxy, int); extern void seemimic(struct monst *) NONNULLARG1; extern void normal_shape(struct monst *) NONNULLARG1; +extern void alloc_itermonarr(unsigned); extern void iter_mons_safe(boolean (*)(struct monst *)); extern void iter_mons(void (*)(struct monst *)); extern struct monst *get_iter_mons(boolean (*)(struct monst *)); diff --git a/src/mon.c b/src/mon.c index 3a66cc41d..ecdbfd3a7 100644 --- a/src/mon.c +++ b/src/mon.c @@ -4102,6 +4102,34 @@ normal_shape(struct monst *mon) } } +/* freed by freedynamicdata() when game ends; doesn't need to be struct g */ +static struct monst **itermonarr = NULL; +static unsigned itermonsiz = 0; /* size in 'monst *' pointers */ + +/* manage itermonarr; it used to be allocated and freed every time the + monster movement loop ran; now, keep it around most of the time */ +void +alloc_itermonarr(unsigned count) +{ + /* if count is 0 or bigger than itemarrsiz or much smaller than + itemarrsiz, release itermonarr (add reset itermarrsiz to 0) */ + if (!count || count > itermonsiz || count + 40 < itermonsiz) { + if (itermonarr) + free((genericptr_t) itermonarr), itermonarr = NULL; + itermonsiz = 0; + } + /* when count is more than itermonsiz (including when that just + got reset to 0), allocate a new instance of itermonarr; + implies that count is greater than 0 */ + if (count > itermonsiz) { + /* overallocate to reduce free/alloc-again thrashing when the + number of monsters varies from turn to turn */ + itermonsiz = count + 20; + itermonarr = (struct monst **) alloc( + itermonsiz * sizeof (struct monst *)); + } +} + /* Iterate all monsters on the level, even dead or off-map ones, calling bfunc() for each monster. If bfunc() returns TRUE, stop iterating. If the game ends during the call to bfunc(), then freedynamicdata() @@ -4112,27 +4140,24 @@ normal_shape(struct monst *mon) void iter_mons_safe(boolean (*bfunc)(struct monst *)) { - struct monst **monarr, *mtmp; - int i, nmons; + struct monst *mtmp; + unsigned i, nmons; for (nmons = 0, mtmp = fmon; mtmp; mtmp = mtmp->nmon) nmons++; - if (nmons) { - monarr = (struct monst **) alloc(nmons * sizeof (struct monst *)); - gi.itermonarr = monarr; /* accessible to freedynamicdata() */ + /* make sure itermonarr[] is big enough to hold nmons entries */ + alloc_itermonarr(nmons); + if (nmons) { for (i = 0, mtmp = fmon; mtmp; mtmp = mtmp->nmon) - monarr[i++] = mtmp; + itermonarr[i++] = mtmp; for (i = 0; i < nmons; i++) { - mtmp = monarr[i]; + mtmp = itermonarr[i]; if ((*bfunc)(mtmp)) break; } - - free(monarr); - gi.itermonarr = NULL; } return; } diff --git a/src/save.c b/src/save.c index fd8c76f39..9d832b73d 100644 --- a/src/save.c +++ b/src/save.c @@ -1184,8 +1184,7 @@ freedynamicdata(void) /* move-specific data */ dmonsfree(); /* release dead monsters */ - if (gi.itermonarr) - free((genericptr_t) gi.itermonarr), gi.itermonarr = NULL; + alloc_itermonarr(0U); /* a request of 0 releases existing allocation */ /* level-specific data */ done_object_cleanup(); /* maybe force some OBJ_FREE items onto map */