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:
parent
18c1326be9
commit
c12cb2f9bb
7 changed files with 68 additions and 24 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)) ) )
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue