/* =============== Com_TouchMemory Touch all known used data to make sure it is paged in =============== */ void Com_TouchMemory( void ) { int start, end; int i, j; int sum; int totalTouched; Z_Validate(); start = Sys_Milliseconds(); sum = 0; totalTouched=0; zoneHeader_t *pMemory = TheZone.Header.pNext; while (pMemory) { byte *pMem = (byte *) &pMemory[1]; j = pMemory->iSize >> 2; for (i=0; i<j; i+=64){ sum += ((int*)pMem)[i]; } totalTouched+=pMemory->iSize; pMemory = pMemory->pNext; } end = Sys_Milliseconds(); Com_Printf( "Com_TouchMemory: %i bytes, %i msec\n", totalTouched, end - start ); }
/* =============== Com_TouchMemory Touch all known used data to make sure it is paged in =============== */ void Com_TouchMemory( void ) { // int start, end; int i, j; int sum; // start = Sys_Milliseconds(); Z_Validate(); sum = 0; zoneHeader_t *pMemory = TheZone.Header.pNext; while (pMemory) { byte *pMem = (byte *) &pMemory[1]; j = pMemory->iSize >> 2; for (i=0; i<j; i+=64){ sum += ((int*)pMem)[i]; } pMemory = pMemory->pNext; } // end = Sys_Milliseconds(); // Com_Printf( "Com_TouchMemory: %i msec\n", end - start ); }
/* ======================== Z_FreeTags ======================== */ void Z_FreeTags(memtag_t tag) { zhead_t *z, *n; Z_FOR_EACH_SAFE(z, n) { Z_Validate(z, __func__); if (z->tag == tag) { Z_Free(z + 1); } }
/* ======================== Z_Realloc ======================== */ void *Z_Realloc(void *ptr, size_t size) { zhead_t *z; if (!ptr) { return Z_Malloc(size); } if (!size) { Z_Free(ptr); return NULL; } z = (zhead_t *)ptr - 1; Z_Validate(z, __func__); if (size > INT_MAX) { Com_Error(ERR_FATAL, "%s: bad size", __func__); } size += sizeof(*z); if (z->size == size) { return z + 1; } if (z->tag == TAG_STATIC) { Com_Error(ERR_FATAL, "%s: couldn't realloc static memory", __func__); } Z_CountFree(z); z = realloc(z, size); if (!z) { Com_Error(ERR_FATAL, "%s: couldn't realloc %"PRIz" bytes", __func__, size); } z->size = size; z->prev->next = z; z->next->prev = z; Z_CountAlloc(z); return z + 1; }
void Z_LeakTest(memtag_t tag) { zhead_t *z; size_t numLeaks = 0, numBytes = 0; Z_FOR_EACH(z) { Z_Validate(z, __func__); if (z->tag == tag) { numLeaks++; numBytes += z->size; } } if (numLeaks) { Com_WPrintf("************* Z_LeakTest *************\n" "%s leaked %"PRIz" bytes of memory (%"PRIz" object%s)\n" "**************************************\n", z_tagnames[tag < TAG_MAX ? tag : TAG_FREE], numBytes, numLeaks, numLeaks == 1 ? "" : "s"); } }
/* ======================== Z_Free ======================== */ void Z_Free(void *ptr) { zhead_t *z; if (!ptr) { return; } z = (zhead_t *)ptr - 1; Z_Validate(z, __func__); Z_CountFree(z); if (z->tag != TAG_STATIC) { z->prev->next = z->next; z->next->prev = z->prev; z->magic = 0xdead; z->tag = TAG_FREE; free(z); } }
void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit) #endif { gbMemFreeupOccured = qfalse; if (iSize == 0) { zoneHeader_t *pMemory = (zoneHeader_t *) &gZeroMalloc; return &pMemory[1]; } // Add in tracking info and round to a longword... (ignore longword aligning now we're not using contiguous blocks) // // int iRealSize = (iSize + sizeof(zoneHeader_t) + sizeof(zoneTail_t) + 3) & 0xfffffffc; int iRealSize = (iSize + sizeof(zoneHeader_t) + sizeof(zoneTail_t)); // Allocate a chunk... // zoneHeader_t *pMemory = NULL; while (pMemory == NULL) { #ifdef _WIN32 if (gbMemFreeupOccured) { Sleep(100); // sleep for 1/10 of a second, so Windows has a chance to shuffle mem to de-swiss-cheese it } #endif pMemory = (zoneHeader_t *) malloc ( iRealSize ); if (!pMemory) { // new bit, if we fail to malloc memory, try dumping some of the cached stuff that's non-vital and try again... // // ditch the BSP cache... // if (CM_DeleteCachedMap(qfalse)) { gbMemFreeupOccured = qtrue; continue; // we've just ditched a whole load of memory, so try again with the malloc } // ditch any sounds not used on this level... // extern qboolean SND_RegisterAudio_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel); if (SND_RegisterAudio_LevelLoadEnd(qtrue)) { gbMemFreeupOccured = qtrue; continue; // we've dropped at least one sound, so try again with the malloc } // ditch any image_t's (and associated GL texture mem) not used on this level... // extern qboolean RE_RegisterImages_LevelLoadEnd(void); if (RE_RegisterImages_LevelLoadEnd()) { gbMemFreeupOccured = qtrue; continue; // we've dropped at least one image, so try again with the malloc } // ditch the model-binaries cache... (must be getting desperate here!) // extern qboolean RE_RegisterModels_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel); if (RE_RegisterModels_LevelLoadEnd(qtrue)) { gbMemFreeupOccured = qtrue; continue; } // as a last panic measure, dump all the audio memory, but not if we're in the audio loader // (which is annoying, but I'm not sure how to ensure we're not dumping any memory needed by the sound // currently being loaded if that was the case)... // // note that this keeps querying until it's freed up as many bytes as the requested size, but freeing // several small blocks might not mean that one larger one is satisfiable after freeup, however that'll // just make it go round again and try for freeing up another bunch of blocks until the total is satisfied // again (though this will have freed twice the requested amount in that case), so it'll either work // eventually or not free up enough and drop through to the final ERR_DROP. No worries... // extern qboolean gbInsideLoadSound; extern int SND_FreeOldestSound(void); // I had to add a void-arg version of this because of link issues, sigh if (!gbInsideLoadSound) { int iBytesFreed = SND_FreeOldestSound(); if (iBytesFreed) { int iTheseBytesFreed = 0; while ( (iTheseBytesFreed = SND_FreeOldestSound()) != 0) { iBytesFreed += iTheseBytesFreed; if (iBytesFreed >= iRealSize) break; // early opt-out since we've managed to recover enough (mem-contiguity issues aside) } gbMemFreeupOccured = qtrue; continue; } } // sigh, dunno what else to try, I guess we'll have to give up and report this as an out-of-mem error... // // findlabel: "recovermem" Com_Printf(S_COLOR_RED"Z_Malloc(): Failed to alloc %d bytes (TAG_%s) !!!!!\n", iSize, psTagStrings[eTag]); Z_Details_f(); Com_Error(ERR_FATAL,"(Repeat): Z_Malloc(): Failed to alloc %d bytes (TAG_%s) !!!!!\n", iSize, psTagStrings[eTag]); return NULL; } } #ifdef DEBUG_ZONE_ALLOCS extern char *Filename_WithoutPath(const char *psFilename); Q_strncpyz(pMemory->sSrcFileBaseName, Filename_WithoutPath(psFile), sizeof(pMemory->sSrcFileBaseName)); pMemory->iSrcFileLineNum = iLine; pMemory->sOptionalLabel[0] = '\0'; pMemory->iSnapshotNumber = giZoneSnaphotNum; #endif // Link in pMemory->iMagic = ZONE_MAGIC; pMemory->eTag = eTag; pMemory->iSize = iSize; pMemory->pNext = TheZone.Header.pNext; TheZone.Header.pNext = pMemory; if (pMemory->pNext) { pMemory->pNext->pPrev = pMemory; } pMemory->pPrev = &TheZone.Header; // // add tail... // ZoneTailFromHeader(pMemory)->iMagic = ZONE_MAGIC; // Update stats... // TheZone.Stats.iCurrent += iSize; TheZone.Stats.iCount++; TheZone.Stats.iSizesPerTag [eTag] += iSize; TheZone.Stats.iCountsPerTag [eTag]++; if (TheZone.Stats.iCurrent > TheZone.Stats.iPeak) { TheZone.Stats.iPeak = TheZone.Stats.iCurrent; } #ifdef DETAILED_ZONE_DEBUG_CODE mapAllocatedZones[pMemory]++; #endif Z_Validate(); // check for corruption void *pvReturnMem = &pMemory[1]; if (bZeroit) { memset(pvReturnMem, 0, iSize); } return pvReturnMem; }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ void SV_SpawnServer( char *server, ForceReload_e eForceReload, qboolean bAllowScreenDissolve ) { int i; int checksum; // The following fixes for potential issues only work on Xbox #ifdef _XBOX extern qboolean stop_icarus; stop_icarus = qfalse; //Broken scripts may leave the player locked. I think that's always bad. extern qboolean player_locked; player_locked = qfalse; //If you quit while in Matrix Mode, this never gets cleared! extern qboolean MatrixMode; MatrixMode = qfalse; // Temporary code to turn on HDR effect for specific maps only if (!Q_stricmp(server, "t3_rift")) { Cvar_Set( "r_hdreffect", "1" ); } else { Cvar_Set( "r_hdreffect", "0" ); } #endif RE_RegisterMedia_LevelLoadBegin( server, eForceReload, bAllowScreenDissolve ); Cvar_SetValue( "cl_paused", 0 ); Cvar_Set( "timescale", "1" );//jic we were skipping // shut down the existing game if it is running SV_ShutdownGameProgs(qtrue); Com_Printf ("------ Server Initialization ------\n%s\n", com_version->string); Com_Printf ("Server: %s\n",server); #ifdef _XBOX // disable vsync during load for speed qglDisable(GL_VSYNC); #endif // don't let sound stutter and dump all stuff on the hunk CL_MapLoading(); if (!CM_SameMap(server)) { //rww - only clear if not loading the same map CM_ClearMap(); } #ifndef _XBOX else if (CM_HasTerrain()) { //always clear when going between maps with terrain CM_ClearMap(); } #endif // Miniheap never changes sizes, so I just put it really early in mem. G2VertSpaceServer->ResetHeap(); #ifdef _XBOX // Deletes all textures R_DeleteTextures(); #endif Hunk_Clear(); // Moved up from below to help reduce fragmentation if (svs.snapshotEntities) { Z_Free(svs.snapshotEntities); svs.snapshotEntities = NULL; } // wipe the entire per-level structure // Also moved up, trying to do all freeing before new allocs for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( sv.configstrings[i] ) { Z_Free( sv.configstrings[i] ); sv.configstrings[i] = NULL; } } #ifdef _XBOX SV_ClearLastLevel(); #endif // Collect all the small allocations done by the cvar system // This frees, then allocates. Make it the last thing before other // allocations begin! Cvar_Defrag(); /* This is useful for debugging memory fragmentation. Please don't remove it. */ #ifdef _XBOX // We've over-freed the info array above, this puts it back into a working state Ghoul2InfoArray_Reset(); extern void Z_DumpMemMap_f(void); extern void Z_Details_f(void); extern void Z_TagPointers(memtag_t); Z_DumpMemMap_f(); // Z_TagPointers(TAG_ALL); Z_Details_f(); #endif // init client structures and svs.numSnapshotEntities // This is moved down quite a bit, but should be safe. And keeps // svs.clients right at the beginning of memory if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } // clear out those shaders, images and Models R_InitImages(); R_InitShaders(); R_ModelInit(); // allocate the snapshot entities svs.snapshotEntities = (entityState_t *) Z_Malloc (sizeof(entityState_t)*svs.numSnapshotEntities, TAG_CLIENTS, qtrue ); Music_SetLevelName(server); // toggle the server bit so clients can detect that a // server has changed //!@ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", va("map %s", server) ); memset (&sv, 0, sizeof(sv)); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } sv.time = 1000; G2API_SetTime(sv.time,G2T_SV_TIME); #ifdef _XBOX CL_StartHunkUsers(); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum ); RE_LoadWorldMap(va("maps/%s.bsp", server)); #else CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum, qfalse ); #endif // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); } #ifndef __NO_JK2 if(!Cvar_VariableIntegerValue("com_jk2")) #endif ge->ConnectNavs(sv_mapname->string, sv_mapChecksum->integer); // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<1 ; i++) { // clear all time counters, because we have reset sv.time svs.clients[i].lastPacketTime = 0; svs.clients[i].lastConnectTime = 0; svs.clients[i].nextSnapshotTime = 0; // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; // connect the client again denied = ge->ClientConnect( i, qfalse, eNO/*qfalse*/ ); // firstTime = qfalse, qbFromSavedGame if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { svs.clients[i].state = CS_CONNECTED; // when we get the next packet from a connected client, // the new gamestate will be sent } } } // run another frame to allow things to look at all connected clients ge->RunFrame( sv.time ); sv.time += 100; G2API_SetTime(sv.time,G2T_SV_TIME); // save systeminfo and serverinfo strings SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; // send a heartbeat now so the master will get up to date info svs.nextHeartbeatTime = -9999999; Hunk_SetMark(); Z_Validate(); Z_Validate(); Z_Validate(); Com_Printf ("-----------------------------------\n"); }
/* ================ SV_SpawnServer Change the server to a new map, taking all connected clients along with it. ================ */ void SV_SpawnServer( const char *server, ForceReload_e eForceReload, qboolean bAllowScreenDissolve ) { int i; int checksum; re.RegisterMedia_LevelLoadBegin( server, eForceReload, bAllowScreenDissolve ); Cvar_SetValue( "cl_paused", 0 ); Cvar_Set( "timescale", "1" );//jic we were skipping // shut down the existing game if it is running SV_ShutdownGameProgs(qtrue); Com_Printf ("------ Server Initialization ------\n%s\n", com_version->string); Com_Printf ("Server: %s\n",server); // Moved up from below to help reduce fragmentation if (svs.snapshotEntities) { Z_Free(svs.snapshotEntities); svs.snapshotEntities = NULL; } // don't let sound stutter and dump all stuff on the hunk CL_MapLoading(); if (!CM_SameMap(server)) { //rww - only clear if not loading the same map CM_ClearMap(); } else if (CM_HasTerrain()) { //always clear when going between maps with terrain CM_ClearMap(); } // Miniheap never changes sizes, so I just put it really early in mem. G2VertSpaceServer->ResetHeap(); Hunk_Clear(); // wipe the entire per-level structure // Also moved up, trying to do all freeing before new allocs for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { if ( sv.configstrings[i] ) { Z_Free( sv.configstrings[i] ); sv.configstrings[i] = NULL; } } // Collect all the small allocations done by the cvar system // This frees, then allocates. Make it the last thing before other // allocations begin! Cvar_Defrag(); /* This is useful for debugging memory fragmentation. Please don't remove it. */ // init client structures and svs.numSnapshotEntities // This is moved down quite a bit, but should be safe. And keeps // svs.clients right at the beginning of memory if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } // clear out those shaders, images and Models /*R_InitImages(); R_InitShaders(); R_ModelInit();*/ re.SVModelInit(); // allocate the snapshot entities svs.snapshotEntities = (entityState_t *) Z_Malloc (sizeof(entityState_t)*svs.numSnapshotEntities, TAG_CLIENTS, qtrue ); Music_SetLevelName(server); // toggle the server bit so clients can detect that a // server has changed //!@ svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; // set nextmap to the same map, but it may be overriden // by the game startup or another console command Cvar_Set( "nextmap", va("map %s", server) ); memset (&sv, 0, sizeof(sv)); for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { sv.configstrings[i] = CopyString(""); } sv.time = 1000; re.G2API_SetTime(sv.time,G2T_SV_TIME); CM_LoadMap( va("maps/%s.bsp", server), qfalse, &checksum, qfalse ); // set serverinfo visible name Cvar_Set( "mapname", server ); Cvar_Set( "sv_mapChecksum", va("%i",checksum) ); // serverid should be different each time sv.serverId = com_frameTime; Cvar_Set( "sv_serverid", va("%i", sv.serverId ) ); // clear physics interaction links SV_ClearWorld (); // media configstring setting should be done during // the loading stage, so connected clients don't have // to load during actual gameplay sv.state = SS_LOADING; // load and spawn all other entities SV_InitGameProgs(); // run a few frames to allow everything to settle for ( i = 0 ;i < 3 ; i++ ) { ge->RunFrame( sv.time ); sv.time += 100; re.G2API_SetTime(sv.time,G2T_SV_TIME); } #ifndef JK2_MODE ge->ConnectNavs(sv_mapname->string, sv_mapChecksum->integer); #endif // create a baseline for more efficient communications SV_CreateBaseline (); for (i=0 ; i<1 ; i++) { // clear all time counters, because we have reset sv.time svs.clients[i].lastPacketTime = 0; svs.clients[i].lastConnectTime = 0; svs.clients[i].nextSnapshotTime = 0; // send the new gamestate to all connected clients if (svs.clients[i].state >= CS_CONNECTED) { char *denied; // connect the client again denied = ge->ClientConnect( i, qfalse, eNO/*qfalse*/ ); // firstTime = qfalse, qbFromSavedGame if ( denied ) { // this generally shouldn't happen, because the client // was connected before the level change SV_DropClient( &svs.clients[i], denied ); } else { svs.clients[i].state = CS_CONNECTED; // when we get the next packet from a connected client, // the new gamestate will be sent } } } // run another frame to allow things to look at all connected clients ge->RunFrame( sv.time ); sv.time += 100; re.G2API_SetTime(sv.time,G2T_SV_TIME); // save systeminfo and serverinfo strings SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString( CVAR_SYSTEMINFO ) ); cvar_modifiedFlags &= ~CVAR_SYSTEMINFO; SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) ); cvar_modifiedFlags &= ~CVAR_SERVERINFO; // any media configstring setting now should issue a warning // and any configstring changes should be reliably transmitted // to all clients sv.state = SS_GAME; Hunk_SetMark(); Z_Validate(); Z_Validate(); Z_Validate(); Com_Printf ("-----------------------------------\n"); }