From 72280186bf2c266f64379021de84d13e41363392 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Jan 2021 18:58:26 +0900 Subject: [PATCH] [qfvis] Use cmem for memory management While the main bulk of the improvement (36s down from 42s for gmsp3v2.bsp on my i7-6850K) comes from using a high-tide allocator for the windings (which necessitated using a fixed size), it is ever so slightly faster than using malloc as the back-end. --- include/QF/cmem.h | 42 ++++++++++++++++++++++++++++++++++++ tools/qfvis/include/vis.h | 15 +++++++------ tools/qfvis/source/flow.c | 44 ++++++++++++++++++++------------------ tools/qfvis/source/qfvis.c | 38 +++++++++++++++++++------------- 4 files changed, 97 insertions(+), 42 deletions(-) diff --git a/include/QF/cmem.h b/include/QF/cmem.h index f9c47d4c1..1f81bf298 100644 --- a/include/QF/cmem.h +++ b/include/QF/cmem.h @@ -115,4 +115,46 @@ void delete_memsuper (memsuper_t *super); void *cmemalloc (memsuper_t *super, size_t size); void cmemfree (memsuper_t *super, void *mem); +/** High-tide structure allocator for use in linked lists. + + Using a free-list with the name of \c NAME_freelist, return a single + element. + The type of the element must be a structure with a field named \c next. + When the free-list is empty, memory is claimed from the system in blocks. + Elements may be returned to the pool by linking them into the free-list. + + \param s The number of structures in the block. + \param t The structure type. + \param n The \c NAME portion of the \c NAME_freelist free-list. + \param super The memsuper_t super block from which to allocate memory. + + \hideinitializer +*/ +#define CMEMALLOC(s, t, n, super) \ + ({ \ + if (!n##_freelist) { \ + int i; \ + n##_freelist = cmemalloc ((super), (s) * sizeof (t)); \ + for (i = 0; i < (s) - 1; i++) \ + n##_freelist[i].next = &n##_freelist[i + 1]; \ + n##_freelist[i].next = 0; \ + } \ + t *v = n##_freelist; \ + n##_freelist = n##_freelist->next; \ + v; \ + }) + +/** Free a block allocated by #ALLOC + + \param n The \c NAME portion of the \c NAME_freelist free-list. + \param p The pointer to the block to be freed. + + \hideinitializer +*/ +#define CMEMFREE(n, p) \ + do { \ + p->next = n##_freelist; \ + n##_freelist = p; \ + } while (0) + #endif//__QF_cmem_h diff --git a/tools/qfvis/include/vis.h b/tools/qfvis/include/vis.h index dc24d17f4..6b96f4b3c 100644 --- a/tools/qfvis/include/vis.h +++ b/tools/qfvis/include/vis.h @@ -82,10 +82,11 @@ extern pthread_rwlock_t *portal_locks; #define MAX_POINTS_ON_WINDING 64 #define MAX_PORTALS_ON_CLUSTER 128 -typedef struct { +typedef struct winding_s { + struct winding_s *next; qboolean original; // don't free, it's part of the portal int numpoints; - vec3_t points[8]; // variable sized + vec3_t points[MAX_PORTALS_ON_CLUSTER]; // variable sized } winding_t; typedef enum { @@ -158,7 +159,9 @@ typedef struct threaddata_s { portal_t *base; ///< portal for which this thread is being run pstack_t pstack_head; sep_t *sep_freelist; ///< per-thread list of free separators + winding_t *winding_freelist; ///< per-thread list of free windings set_pool_t set_pool; + struct memsuper_s *memsuper; } threaddata_t; typedef struct { @@ -179,10 +182,10 @@ extern cluster_t *clusters; extern int *leafcluster; extern byte *uncompressed; -void FreeWinding (winding_t *w); -winding_t *NewWinding (int points); -winding_t *ClipWinding (winding_t *in, const plane_t *split, qboolean keepon); -winding_t *CopyWinding (const winding_t *w); +void FreeWinding (threaddata_t *thread, winding_t *w); +winding_t *NewWinding (threaddata_t *thread, int points); +winding_t *ClipWinding (threaddata_t *thread, winding_t *in, const plane_t *split, qboolean keepon); +winding_t *CopyWinding (threaddata_t *thread, const winding_t *w); void ClusterFlow (int clusternum); void PortalBase (basethread_t *thread, portal_t *portal); diff --git a/tools/qfvis/source/flow.c b/tools/qfvis/source/flow.c index 030ca7a43..520976637 100644 --- a/tools/qfvis/source/flow.c +++ b/tools/qfvis/source/flow.c @@ -48,8 +48,8 @@ #include #include -#include "QF/alloc.h" #include "QF/bspfile.h" +#include "QF/cmem.h" #include "QF/cmd.h" #include "QF/mathlib.h" #include "QF/quakefs.h" @@ -90,14 +90,14 @@ new_separator (threaddata_t *thread) { sep_t *sep; - ALLOC (128, sep_t, thread->sep, sep); + sep = CMEMALLOC (32, sep_t, thread->sep, thread->memsuper); return sep; } static void delete_separator (threaddata_t *thread, sep_t *sep) { - FREE (thread->sep, sep); + CMEMFREE (thread->sep, sep); } static void @@ -247,12 +247,12 @@ FindSeparators (threaddata_t *thread, } static winding_t * -ClipToSeparators (const sep_t *separators, winding_t *target) +ClipToSeparators (threaddata_t *thread, const sep_t *separators, winding_t *target) { const sep_t *sep; for (sep = separators; target && sep; sep = sep->next) { - target = ClipWinding (target, &sep->plane, false); + target = ClipWinding (thread, target, &sep->plane, false); } return target; } @@ -360,7 +360,7 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack) thread->stats.portalcheck++; target_winding = target_portal->winding; - target_winding = ClipWinding (target_winding, source_plane, false); + target_winding = ClipWinding (thread, target_winding, source_plane, false); if (!target_winding) continue; @@ -374,21 +374,21 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack) stack->pass_portal = target_portal; RecursiveClusterFlow (target_portal->cluster, thread, stack); - FreeWinding (target_winding); + FreeWinding (thread, target_winding); continue; } - target_winding = ClipWinding (target_winding, pass_plane, false); + target_winding = ClipWinding (thread, target_winding, pass_plane, false); if (!target_winding) continue; // copy source_winding because it likely is already a copy and thus // if it gets clipped away, earlier stack levels will get corrupted - source_winding = CopyWinding (prevstack->source_winding); + source_winding = CopyWinding (thread, prevstack->source_winding); - source_winding = ClipWinding (source_winding, &backplane, false); + source_winding = ClipWinding (thread, source_winding, &backplane, false); if (!source_winding) { - FreeWinding (target_winding); + FreeWinding (thread, target_winding); continue; } @@ -402,11 +402,12 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack) source_winding, *source_plane, pass_winding, 0); - target_winding = ClipToSeparators (stack->separators[0], + target_winding = ClipToSeparators (thread, + stack->separators[0], target_winding); if (!target_winding) { thread->stats.targetclipped++; - FreeWinding (source_winding); + FreeWinding (thread, source_winding); continue; } if (target_winding != old) @@ -420,11 +421,12 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack) pass_winding, *pass_plane, source_winding, 1); - target_winding = ClipToSeparators (stack->separators[1], + target_winding = ClipToSeparators (thread, + stack->separators[1], target_winding); if (!target_winding) { thread->stats.targetclipped++; - FreeWinding (source_winding); + FreeWinding (thread, source_winding); continue; } if (target_winding != old) @@ -438,11 +440,11 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack) sep = FindSeparators (thread, target_winding, target_portal->plane, pass_winding, 0); - source_winding = ClipToSeparators (sep, source_winding); + source_winding = ClipToSeparators (thread, sep, source_winding); free_separators (thread, sep); if (!source_winding) { thread->stats.sourceclipped++; - FreeWinding (target_winding); + FreeWinding (thread, target_winding); continue; } if (source_winding != old) @@ -454,11 +456,11 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack) sep_t *sep; sep = FindSeparators (thread, pass_winding, *pass_plane, target_winding, 1); - source_winding = ClipToSeparators (sep, source_winding); + source_winding = ClipToSeparators (thread, sep, source_winding); free_separators (thread, sep); if (!source_winding) { thread->stats.sourceclipped++; - FreeWinding (target_winding); + FreeWinding (thread, target_winding); continue; } if (source_winding != old) @@ -476,8 +478,8 @@ RecursiveClusterFlow (int clusternum, threaddata_t *thread, pstack_t *prevstack) // flow through it for real RecursiveClusterFlow (target_portal->cluster, thread, stack); - FreeWinding (source_winding); - FreeWinding (target_winding); + FreeWinding (thread, source_winding); + FreeWinding (thread, target_winding); } free_separators (thread, stack->separators[1]); free_separators (thread, stack->separators[0]); diff --git a/tools/qfvis/source/qfvis.c b/tools/qfvis/source/qfvis.c index c62eabbcc..3a49e53c1 100644 --- a/tools/qfvis/source/qfvis.c +++ b/tools/qfvis/source/qfvis.c @@ -51,6 +51,7 @@ #include "QF/bspfile.h" #include "QF/cmd.h" +#include "QF/cmem.h" #include "QF/dstring.h" #include "QF/mathlib.h" #include "QF/qtypes.h" @@ -71,6 +72,7 @@ bsp_t *bsp; options_t options; +static threaddata_t main_thread; static visstat_t stats; int base_mightsee; @@ -144,7 +146,7 @@ PlaneFromWinding (winding_t *winding, plane_t *plane) } winding_t * -NewWinding (int points) +NewWinding (threaddata_t *thread, int points) { winding_t *winding; size_t size; @@ -153,38 +155,40 @@ NewWinding (int points) Sys_Error ("NewWinding: %i points", points); size = field_offset (winding_t, points[points]); - winding = calloc (1, size); + winding = CMEMALLOC (13, winding_t, thread->winding, thread->memsuper); + memset (winding, 0, size); return winding; } void -FreeWinding (winding_t *w) +FreeWinding (threaddata_t *thread, winding_t *w) { - if (!w->original) - free (w); + if (!w->original) { + CMEMFREE (thread->winding, w); + } } winding_t * -CopyWinding (const winding_t *w) +CopyWinding (threaddata_t *thread, const winding_t *w) { size_t size; winding_t *copy; size = field_offset (winding_t, points[w->numpoints]); - copy = malloc (size); + copy = CMEMALLOC (13, winding_t, thread->winding, thread->memsuper); memcpy (copy, w, size); copy->original = false; return copy; } static winding_t * -NewFlippedWinding (const winding_t *w) +NewFlippedWinding (threaddata_t *thread, const winding_t *w) { winding_t *flipped; int i; - flipped = NewWinding (w->numpoints); + flipped = NewWinding (thread, w->numpoints); for (i = 0; i < w->numpoints; i++) VectorCopy (w->points[i], flipped->points[w->numpoints - 1 - i]); flipped->numpoints = w->numpoints; @@ -203,7 +207,7 @@ NewFlippedWinding (const winding_t *w) it will be clipped away. */ winding_t * -ClipWinding (winding_t *in, const plane_t *split, qboolean keepon) +ClipWinding (threaddata_t *thread, winding_t *in, const plane_t *split, qboolean keepon) { int maxpts, i, j; int counts[3], sides[MAX_POINTS_ON_WINDING]; @@ -236,7 +240,7 @@ ClipWinding (winding_t *in, const plane_t *split, qboolean keepon) return in; if (!counts[0]) { - FreeWinding (in); + FreeWinding (thread, in); return NULL; } if (!counts[1]) @@ -244,7 +248,7 @@ ClipWinding (winding_t *in, const plane_t *split, qboolean keepon) maxpts = in->numpoints + 4; // can't use counts[0] + 2 because // of fp grouping errors - neww = NewWinding (maxpts); + neww = NewWinding (thread, maxpts); for (i = 0; i < in->numpoints; i++) { p1 = in->points[i]; @@ -284,7 +288,7 @@ ClipWinding (winding_t *in, const plane_t *split, qboolean keepon) if (neww->numpoints > maxpts) Sys_Error ("ClipWinding: points exceeded estimate"); // free the original winding - FreeWinding (in); + FreeWinding (thread, in); return neww; } @@ -384,6 +388,7 @@ LeafThread (void *_thread) memset (&data, 0, sizeof (data)); set_pool_init (&data.set_pool); + data.memsuper = new_memsuper (); do { portal = GetNextPortal (); if (!portal) @@ -408,6 +413,7 @@ LeafThread (void *_thread) printf ("thread %d done\n", thread); if (working) working[thread] = -1; + delete_memsuper (data.memsuper); return NULL; } @@ -1033,7 +1039,7 @@ LoadPortals (char *name) || (unsigned) clusternums[1] > (unsigned) portalclusters) Sys_Error ("LoadPortals: reading portal %i", i); - winding = portal->winding = NewWinding (numpoints); + winding = portal->winding = NewWinding (&main_thread, numpoints); winding->original = true; winding->numpoints = numpoints; @@ -1085,7 +1091,7 @@ LoadPortals (char *name) // Use a flipped winding for the reverse portal so the winding // direction and plane normal match. - portal->winding = NewFlippedWinding (winding); + portal->winding = NewFlippedWinding (&main_thread, winding); portal->winding->original = true; portal->plane = plane; portal->cluster = clusternums[0]; @@ -1115,6 +1121,8 @@ main (int argc, char **argv) dstring_t *portalfile = dstring_new (); QFile *f; + main_thread.memsuper = new_memsuper (); + start = Sys_DoubleTime (); this_program = argv[0];