fix pvs/phs memory leak when the same world map is used multiple times without getting flushed.

back off on per-client memory use.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4901 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2015-06-14 12:26:01 +00:00
parent 18c1326be9
commit c12cb2f9bb
7 changed files with 68 additions and 24 deletions

View File

@ -926,6 +926,7 @@ typedef struct model_s
int numtextures;
texture_t **textures;
qbyte *pvs, *phs; // fully expanded and decompressed
qbyte *visdata;
void *vis;
qbyte *lightdata;

View File

@ -157,7 +157,6 @@ typedef struct
int spawned_observer_slots;
model_t *models[MAX_PRECACHE_MODELS];
qbyte *pvs, *phs; // fully expanded and decompressed
struct client_s *skipbprintclient; //SV_BroadcastPrint skips this client

View File

@ -2598,6 +2598,42 @@ void SV_PrecacheList_f(void)
}
}
void SV_MemInfo_f(void)
{
int sz, i, fr, csfr;
laggedpacket_t *lp;
client_t *cl;
Cmd_ExecuteString("mod_memlist;hunkprint", Cmd_ExecLevel);
for (i = 0; i < svs.allocated_client_slots; i++)
{
cl = &svs.clients[i];
if (cl->state)
{
Con_Printf("%s\n", cl->name);
sz = 0;
for (lp = cl->laggedpacket; lp; lp = lp->next)
sz += lp->length;
fr = 0;
if (cl->pendingentbits)
{
int maxents = cl->frameunion.frames[0].entities.max_entities; /*this is the max number of ents updated per frame. we can't track more, so...*/
fr = sizeof(cl)*UPDATE_BACKUP+
sizeof(*cl->pendingentbits)*cl->max_net_ents+
sizeof(unsigned int)*maxents*UPDATE_BACKUP+
sizeof(unsigned int)*maxents*UPDATE_BACKUP;
}
else
fr = (sizeof(client_frame_t)+sizeof(entity_state_t)*cl->frameunion.frames[0].entities.max_entities)*UPDATE_BACKUP;
fr += sizeof(*cl->sentents.entities) * cl->sentents.max_entities;
csfr = sizeof(*cl->csqcentversions) * cl->max_net_ents;
Con_Printf("%i minping=%i frame=%i, csqc=%i\n", sizeof(svs.clients[i]), sz, fr, csfr);
}
}
}
/*
==================
SV_InitOperatorCommands
@ -2683,6 +2719,8 @@ void SV_InitOperatorCommands (void)
Cmd_AddCommand ("pin_delete", SV_Pin_Delete_f);
Cmd_AddCommand ("pin_add", SV_Pin_Add_f);
Cmd_AddCommand("sv_meminfo", SV_MemInfo_f);
// Cmd_AddCommand ("reallyevilhack", SV_ReallyEvilHack_f);
if (isDedicated)

View File

@ -3364,7 +3364,8 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t
{
int cluster;
unsigned char *mask;
if (sv.phs)
qbyte *phs = sv.world.worldmodel->phs;
if (phs)
{
//FIXME: this lookup should be cachable or something.
if (client->edict)
@ -3373,7 +3374,7 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t
cluster = -1; //mvd
if (cluster >= 0)
{
mask = sv.phs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5);
mask = phs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5);
cluster = sv.world.worldmodel->funcs.ClusterForPoint (sv.world.worldmodel, ent->v->origin);
if (cluster >= 0 && !(mask[cluster>>3] & (1<<(cluster&7)) ) )

View File

@ -435,39 +435,41 @@ void SV_CalcPHS (void)
unsigned *dest, *src;
qbyte *scan, *lf;
int count, vcount;
model_t *model = sv.world.worldmodel;
if (sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3)
if (model->pvs || model->fromgame == fg_quake2 || model->fromgame == fg_quake3)
{
//PHS calcs are pointless with Q2 bsps
return;
}
num = sv.world.worldmodel->numclusters;
//FIXME: this can take a significant time on some maps, and should ideally be pushed to a worker thread.
num = model->numclusters;
rowwords = (num+31)>>5;
rowbytes = rowwords*4;
if (!sv_calcphs.ival || (sv_calcphs.ival == 2 && (rowbytes*num >= 0x100000 || (!deathmatch.ival && !coop.ival))))
{
sv.pvs = ZG_Malloc(&sv.world.worldmodel->memgroup, rowbytes*num);
scan = sv.pvs;
model->pvs = ZG_Malloc(&model->memgroup, rowbytes*num);
scan = model->pvs;
for (i=0 ; i<num ; i++, scan+=rowbytes)
{
lf = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, i, scan, rowbytes);
lf = model->funcs.ClusterPVS(model, i, scan, rowbytes);
if (lf != scan)
memcpy (scan, lf, rowbytes);
}
Con_DPrintf("Skipping PHS\n");
sv.phs = NULL;
model->phs = NULL;
return;
}
sv.pvs = ZG_Malloc(&sv.world.worldmodel->memgroup, rowbytes*num);
scan = sv.pvs;
model->pvs = ZG_Malloc(&model->memgroup, rowbytes*num);
scan = model->pvs;
vcount = 0;
for (i=0 ; i<num ; i++, scan+=rowbytes)
{
lf = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, i, scan, rowbytes);
lf = model->funcs.ClusterPVS(model, i, scan, rowbytes);
if (lf != scan)
memcpy (scan, lf, rowbytes);
if (i == 0)
@ -483,7 +485,7 @@ void SV_CalcPHS (void)
if (developer.value)
Con_TPrintf ("Building PHS...\n");
sv.phs = ZG_Malloc (&sv.world.worldmodel->memgroup, rowbytes*num);
model->phs = ZG_Malloc (&model->memgroup, rowbytes*num);
/*this routine takes an exponential amount of time, so cache it if its too big*/
if (rowbytes*num >= 0x100000)
@ -495,7 +497,7 @@ void SV_CalcPHS (void)
VFS_READ(f, hdr, sizeof(hdr));
if (memcmp(hdr, "QPHS\1\0\0\0", 8) || VFS_GETLEN(f) != rowbytes*num + 8)
{
VFS_READ(f, sv.phs, rowbytes*num);
VFS_READ(f, model->phs, rowbytes*num);
VFS_CLOSE(f);
Con_DPrintf("Loaded cached PHS\n");
return;
@ -507,8 +509,8 @@ void SV_CalcPHS (void)
}
count = 0;
scan = sv.pvs;
dest = (unsigned *)sv.phs;
scan = model->pvs;
dest = (unsigned *)model->phs;
for (i=0 ; i<num ; i++, dest += rowwords, scan += rowbytes)
{
memcpy (dest, scan, rowbytes);
@ -527,7 +529,7 @@ void SV_CalcPHS (void)
index = ((j<<3)+k);
if (index >= num)
continue;
src = (unsigned *)sv.pvs + index*rowwords;
src = (unsigned *)model->pvs + index*rowwords;
for (l=0 ; l<rowwords ; l++)
dest[l] |= src[l];
}
@ -546,7 +548,7 @@ void SV_CalcPHS (void)
if (f)
{
VFS_WRITE(f, "QPHS\1\0\0\0", 8);
VFS_WRITE(f, sv.phs, rowbytes*num);
VFS_WRITE(f, model->phs, rowbytes*num);
VFS_CLOSE(f);
Con_Printf("Written PHS cache (%u bytes)\n", rowbytes*num);
}

View File

@ -1828,7 +1828,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
if ((client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))// || ISDPCLIENT(&temp))
{
char *ptr;
int maxents = client->max_net_ents;//maxpacketentities; /*this is the max number of ents updated per frame. we can't track more, so...*/
int maxents = /*client->max_net_ents;//*/maxpacketentities; /*this is the max number of ents updated per frame. we can't track more, so...*/
ptr = Z_Malloc( sizeof(client_frame_t)*UPDATE_BACKUP+
sizeof(*client->pendingentbits)*client->max_net_ents+
sizeof(unsigned int)*maxents*UPDATE_BACKUP+
@ -3862,7 +3862,7 @@ if necessary
void SV_CheckTimeouts (void)
{
int i;
client_t *cl;
client_t *cl, *cont;
float droptime;
int nclients;
@ -3875,7 +3875,10 @@ void SV_CheckTimeouts (void)
{
if (!cl->spectator)
nclients++;
if (cl->netchan.last_received < droptime && cl->netchan.remote_address.type != NA_LOOPBACK && cl->protocol != SCP_BAD)
cont = cl;
if (cont->controller)
cont = cont->controller;
if (cont->netchan.last_received < droptime && cl->netchan.remote_address.type != NA_LOOPBACK && cl->protocol != SCP_BAD)
{
SV_BroadcastTPrintf (PRINT_HIGH, "Client %s timed out\n", cl->name);
SV_DropClient (cl);

View File

@ -776,13 +776,13 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
case MULTICAST_PHS_R:
reliable = true; // intentional fallthrough
case MULTICAST_PHS:
if (!sv.phs) /*broadcast if no pvs*/
if (!sv.world.worldmodel->phs) /*broadcast if no pvs*/
mask = NULL;
else
{
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin);
if (cluster >= 0)
mask = sv.phs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5);
mask = sv.world.worldmodel->phs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5);
else
mask = NULL;
}
@ -793,7 +793,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
case MULTICAST_PVS:
cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin);
if (cluster >= 0)
mask = sv.pvs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5);
mask = sv.world.worldmodel->pvs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5);
else
mask = NULL;
break;