/* * Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* * $Logfile: /DescentIII/Main/rtperformance/rtperformance.cpp $ * $Revision: 9 $ * $Date: 10/21/99 3:21p $ * $Author: Kevin $ * * Run time performance lib * * $Log: /DescentIII/Main/rtperformance/rtperformance.cpp $ * * 9 10/21/99 3:21p Kevin * Mac merge * * 8 5/07/99 6:21p Jeff * hooked up fvi to rtperformance * * 7 4/16/99 4:04a Jeff * fixed up for non-window's builds * * 6 4/16/99 1:59a Jeff * ifdef out windows.h for now windows builds * * 5 10/19/98 7:51p Kevin * performance testing * * 4 10/19/98 2:48p Jeff * changed define for rtp performance...just define USE_RTP in * rtperformance.h in order to enable it * * 3 10/17/98 6:05p Jeff * it helps to write the heading to file * * 2 10/17/98 5:58p Jeff * put in heading * * $NoKeywords: $ */ #if defined(WIN32) #include #endif #include "rtperformance.h" #include "pstypes.h" #include "mono.h" #include "descent.h" #include "manage.h" #include "ddio.h" #include "CFILE.H" #include #include #include #include float rtp_startlog_time; // maximum number of samples before we stop and autoflush #define MAX_RTP_SAMPLES 3800 // this is a little more than whats needed for 2 minutes at 30fps // Internal Global Vars // ------------------------------ INT64 Runtime_performance_flags = RTI_FRAMETIME; INT64 Runtime_performance_clockfreq = 0; INT64 Runtime_performance_frame_counter = 0; unsigned int Runtime_performance_counter = 0; unsigned char Runtime_performance_enabled = 0; tRTFrameInfo RTP_SingleFrame; #ifdef USE_RTP tRTFrameInfo RTP_FrameBuffer[MAX_RTP_SAMPLES]; #endif /* void rtp_WriteBufferLog Writes the buffer of frames to file... */ void rtp_WriteBufferLog(void) { #ifdef USE_RTP Runtime_performance_enabled = 1; // make sure it's enabled for the macros // determine how many frames to write out unsigned int Num_frames; unsigned int counter; char buffer[4096]; Num_frames = std::min(Runtime_performance_counter, MAX_RTP_SAMPLES); // Open the log file for writing ddio_MakePath(buffer, LocalD3Dir, "D3Performance.txt", NULL); CFILE *file = cfopen(buffer, "wt"); if (file) { mprintf((0, "RTP: Recording Log\n")); strcpy(buffer, "FrameNum,FrameTime,RenderFrameTime,MultiFrameTime,MusicFrameTime,AmbientSoundTime,WeatherFrameTime," "PlayerFrameTime,DoorwayFrameTime,LevelGoalFrameTime,MatCenFrameTime,ObjectFrameTime,AIFrameAllTime," "ProcessKeysTime,REN:NumTexturesUploaded,REN:PolysDrawn,OBJ:CT_FlyingTime,OBJ:CT_AIDoFrameTime,OBJ:" "CT_WeaponFrameTime,OBJ:CT_ExplosionFrameTime,OBJ:CT_DebrisFrameTime,OBJ:CT_SplinterFrameTime,OBJ:" "MT_PhsyicsFrameTime,OBJ:MT_WalkingFrame,OBJ:MT_ShockWaveTime,OBJ:DoEffectTime,OBJ:MovePlayerTime," "OBJ:D3XIntervalTime,OBJ:ObjLightTime,FRAME:NormalEventTime,AnimCycle,VisEffectMoveAll," "DoPhysLinkedFrame,ObjDoFrame,NumFVICalls,FVITime"); cf_WriteString(file, buffer); // Loop through all the frames, and write out the data for each frame for (counter = 0; counter < Num_frames; counter++) { tRTFrameInfo *fi = &RTP_FrameBuffer[counter]; double renderframe_time; double multiframe_time; double musicframe_time; double ambsound_frame_time; double weatherframe_time; double playerframe_time; double doorframe_time; double levelgoal_time; double matcenframe_time; double objframe_time; double aiframeall_time; double processkeys_time; double ct_flying_time; double ct_aidoframe_time; double ct_weaponframe_time; double ct_explosionframe_time; double ct_debrisframe_time; double ct_splinterframe_time; double mt_physicsframe_time; double mt_walkingframe_time; double mt_shockwave_time; double obj_doeffect_time; double obj_move_player_time; double obj_d3xint_time; double obj_objlight_time; double normalevent_time; double cycle_anim; double vis_eff_move; double phys_link; double obj_do_frm; double fvi_time; RTP_CLOCKSECONDS(fi->renderframe_time, renderframe_time); RTP_CLOCKSECONDS(fi->multiframe_time, multiframe_time); RTP_CLOCKSECONDS(fi->musicframe_time, musicframe_time); RTP_CLOCKSECONDS(fi->ambsound_frame_time, ambsound_frame_time); RTP_CLOCKSECONDS(fi->weatherframe_time, weatherframe_time); RTP_CLOCKSECONDS(fi->playerframe_time, playerframe_time); RTP_CLOCKSECONDS(fi->doorframe_time, doorframe_time); RTP_CLOCKSECONDS(fi->levelgoal_time, levelgoal_time); RTP_CLOCKSECONDS(fi->matcenframe_time, matcenframe_time); RTP_CLOCKSECONDS(fi->objframe_time, objframe_time); RTP_CLOCKSECONDS(fi->aiframeall_time, aiframeall_time); RTP_CLOCKSECONDS(fi->processkeys_time, processkeys_time); RTP_CLOCKSECONDS(fi->ct_flying_time, ct_flying_time); RTP_CLOCKSECONDS(fi->ct_aidoframe_time, ct_aidoframe_time); RTP_CLOCKSECONDS(fi->ct_weaponframe_time, ct_weaponframe_time); RTP_CLOCKSECONDS(fi->ct_explosionframe_time, ct_explosionframe_time); RTP_CLOCKSECONDS(fi->ct_debrisframe_time, ct_debrisframe_time); RTP_CLOCKSECONDS(fi->ct_splinterframe_time, ct_splinterframe_time); RTP_CLOCKSECONDS(fi->mt_physicsframe_time, mt_physicsframe_time); RTP_CLOCKSECONDS(fi->mt_walkingframe_time, mt_walkingframe_time); RTP_CLOCKSECONDS(fi->mt_shockwave_time, mt_shockwave_time); RTP_CLOCKSECONDS(fi->obj_doeffect_time, obj_doeffect_time); RTP_CLOCKSECONDS(fi->obj_move_player_time, obj_move_player_time); RTP_CLOCKSECONDS(fi->obj_d3xint_time, obj_d3xint_time); RTP_CLOCKSECONDS(fi->obj_objlight_time, obj_objlight_time); RTP_CLOCKSECONDS(fi->normalevent_time, normalevent_time); RTP_CLOCKSECONDS(fi->cycle_anim, cycle_anim); RTP_CLOCKSECONDS(fi->vis_eff_move, vis_eff_move); RTP_CLOCKSECONDS(fi->phys_link, phys_link); RTP_CLOCKSECONDS(fi->obj_do_frm, obj_do_frm); RTP_CLOCKSECONDS(fi->fvi_time, fvi_time); snprintf(buffer, sizeof(buffer), "%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f " "%d %lld", (int)fi->frame_num, fi->frame_time, renderframe_time, multiframe_time, musicframe_time, ambsound_frame_time, weatherframe_time, playerframe_time, doorframe_time, levelgoal_time, matcenframe_time, objframe_time, aiframeall_time, processkeys_time, fi->texture_uploads, fi->polys_drawn, ct_flying_time, ct_aidoframe_time, ct_weaponframe_time, ct_explosionframe_time, ct_debrisframe_time, ct_splinterframe_time, mt_physicsframe_time, mt_walkingframe_time, mt_shockwave_time, obj_doeffect_time, obj_move_player_time, obj_d3xint_time, obj_objlight_time, normalevent_time, cycle_anim, vis_eff_move, phys_link, obj_do_frm, fi->fvi_calls, fi->fvi_time); cf_WriteString(file, buffer); } // Close the log file cfclose(file); } else mprintf((0, "RTP: Unable to open log for writing\n")); #endif } /* void rtp_RecordFrame Calling this will record the data of the frame into the internal log, and prepare for the next frame */ void rtp_RecordFrame(void) { #ifdef USE_RTP if (Runtime_performance_enabled) { // do our saving of information // -------------------------------- RTP_SingleFrame.frame_num = Runtime_performance_frame_counter; // save the frame num // Copy everything into the buffer, and advance the buffer memcpy(&RTP_FrameBuffer[Runtime_performance_counter], &RTP_SingleFrame, sizeof(tRTFrameInfo)); Runtime_performance_counter++; if (Runtime_performance_counter >= MAX_RTP_SAMPLES) { // uh oh, we hit the end of our samples, flush the buffer and stop rtp_StopLog(); } // reset our global struct to zero everything out // ------------------------------------------------ memset(&RTP_SingleFrame, 0, sizeof(tRTFrameInfo)); } // Update the frame counter to the next frame, always Runtime_performance_frame_counter++; #endif } // External Functions // ----------------------------- /* void rtp_Init This function initilizes the runtime performance system so it's ready to be used */ void rtp_Close(void); void rtp_Init(void) { #ifdef USE_RTP Runtime_performance_flags = 0; Runtime_performance_clockfreq = 0; Runtime_performance_frame_counter = 0; Runtime_performance_counter = 0; Runtime_performance_enabled = 0; #ifdef MACINTOSH Runtime_performance_clockfreq = 1000000; // micoseconds #else LARGE_INTEGER freq; if (!QueryPerformanceFrequency(&freq)) { // there is no hi-res clock available....ummmm mprintf((0, "RTP: No Hi-Resolution clock available on this system!!!!!!\n")); // well, this isn't good...what to do, what to do? } // Setup the clock freq....we'll need this info later I guess when converting to seconds Runtime_performance_clockfreq = freq.QuadPart; #endif rtp_EnableFlags(RTI_FRAMETIME); atexit(rtp_Close); #endif } /* void rtp_Close This function shuts down the runtime performance system when the game is done */ void rtp_Close(void) { #ifdef USE_RTP if (Runtime_performance_enabled) { // Save the log out, since it was currently logging rtp_StopLog(); } #endif } /* void rtp_EnableFlags This function enables the performance profiling of whatever flags you pass in */ void rtp_EnableFlags(INT64 flags) { #ifdef USE_RTP Runtime_performance_flags |= flags; #endif } /* void rtp_DisableFlags This function disables the performance profiling of whatever flags you pass in */ void rtp_DisableFlags(INT64 flags) { #ifdef USE_RTP Runtime_performance_flags &= ~flags; #endif } /* void rtp_StartLog Calling this function will reset the log and start a new log, recording immediatly */ void rtp_StartLog(void) { #ifdef USE_RTP mprintf((0, "RTP: Starting Log\n")); Runtime_performance_counter = 0; Runtime_performance_enabled = 1; memset(&RTP_SingleFrame, 0, sizeof(tRTFrameInfo)); rtp_startlog_time = timer_GetTime(); #endif } /* void rtp_StopLog Calling this function will stop the currently processing log and write it out to file. */ void rtp_StopLog(void) { #ifdef USE_RTP mprintf((0, "Recorded performance for %f seconds\n", timer_GetTime() - rtp_startlog_time)); mprintf((0, "RTP: Stopping Log\n")); // Save out the log now rtp_WriteBufferLog(); Runtime_performance_enabled = 0; #endif } /* void rtp_PauseLog Calling this function will pause the log recording until rtp_ResumeLog is called */ void rtp_PauseLog(void) { #ifdef USE_RTP mprintf((0, "RTP: Pausing Log\n")); Runtime_performance_enabled = 0; #endif } /* void rtp_ResumeLog Calling this will resume a paused log, starting at where it left off */ void rtp_ResumeLog(void) { #ifdef USE_RTP mprintf((0, "RTP: Resuming Log\n")); Runtime_performance_enabled = 1; #endif } // Internal Functions // ------------------------------- /* INT64 rtp_GetClock Returns the current hi-resolution clock value...no checking for overflow */ INT64 rtp_GetClock(void) { #ifdef USE_RTP #ifdef MACINTOSH INT64 currentTimeUI = 0; // Get the current time in microseconds Microseconds((UnsignedWide *)(¤tTimeUI)); return currentTimeUI; #else LARGE_INTEGER t; QueryPerformanceCounter(&t); return (INT64)t.QuadPart; #endif #else return 0; #endif }