[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.
This commit is contained in:
Bill Currie 2021-01-01 18:58:26 +09:00
parent 0cdcb64f51
commit 72280186bf
4 changed files with 97 additions and 42 deletions

View File

@ -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

View File

@ -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);

View File

@ -48,8 +48,8 @@
#include <string.h>
#include <stdlib.h>
#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]);

View File

@ -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];