mirror of
https://github.com/electronicarts/CnC_Red_Alert.git
synced 2025-12-16 07:31:39 -05:00
Initial commit of Command & Conquer Red Alert source code.
This commit is contained in:
272
WIN32LIB/SRCDEBUG/WPROFILE.CPP
Normal file
272
WIN32LIB/SRCDEBUG/WPROFILE.CPP
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
** Command & Conquer Red Alert(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Library profiler *
|
||||
* *
|
||||
* File Name : WPROFILE.CPP *
|
||||
* *
|
||||
* Programmer : Steve Tall *
|
||||
* *
|
||||
* Start Date : 11/17/95 *
|
||||
* *
|
||||
* Last Update : November 20th 1995 [ST] *
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Overview: *
|
||||
* *
|
||||
* New System *
|
||||
* ~~~~~~~~~~~ *
|
||||
* *
|
||||
* The new profiler system creates a seperate thread and then starts a timer off there. The *
|
||||
* timer in the second thread uses GetThreadContext to sample the IP address of each user *
|
||||
* thread. This system has the advantage of being able to sample what is happening in all the *
|
||||
* threads we own not just the main thread. Another advantage is that it doesnt require a *
|
||||
* major recompilation. *
|
||||
* The disadvantage is that we dont really know what is going on when the IP is outside the *
|
||||
* scope of our threads - We could be in direct draw, direct sound or even something like the *
|
||||
* VMM and there is no way to tell. *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* Old System *
|
||||
* ~~~~~~~~~~~ *
|
||||
* *
|
||||
* The profiler works by using the function prologue and epilogue hooks available in Watcom *
|
||||
* to register the current functions address in a global variable and then sampling the *
|
||||
* contents of the variable using a windows timer which runs at up to 1000 samples per second.*
|
||||
* *
|
||||
* Compile the code to be sampled with the -ep and -ee flags to enable the prologue (__PRO) *
|
||||
* and epilogue (__EPI) calls to be generated. *
|
||||
* At the beginning of the section to be profiled (just before main loop normally) call the *
|
||||
* Start_Profiler function to start sampling. At the end of the section, call Stop_Profiler *
|
||||
* which will stop the timer and write the profile data to disk in the PROFILE.BIN file. *
|
||||
* *
|
||||
* Use PROFILE.EXE to view the results of the session. *
|
||||
* *
|
||||
* The addition of prologue and epilogue code will slow down the product and the profiler *
|
||||
* allocates a huge buffer for data so it should not be linked in unless it is going to be *
|
||||
* used. *
|
||||
* *
|
||||
* The advantage of the prologue/epilogue approach is that all samples represent valid *
|
||||
* addresses within our code so we get valid results we can use even when the IP is in system *
|
||||
* code. *
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* *
|
||||
* Functions: *
|
||||
* Start_Profiler -- initialises the profiler data and starts gathering data *
|
||||
* Stop_Profiler -- stops the timer and writes the profile data to disk *
|
||||
* *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#define WIN32
|
||||
#ifndef _WIN32 // Denzil 6/2/98 Watcom 11.0 complains without this check
|
||||
#define _WIN32
|
||||
#endif // _WIN32
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <wwstd.h>
|
||||
#include <rawfile.h>
|
||||
#include <file.h>
|
||||
#include "profile.h"
|
||||
#include <vdmdbg.h>
|
||||
#include <timer.h>
|
||||
|
||||
#define PROFILE
|
||||
|
||||
extern "C"{
|
||||
#ifdef PROFILE
|
||||
unsigned ProfileList [PROFILE_RATE*MAX_PROFILE_TIME];
|
||||
#else
|
||||
unsigned ProfileList [2];
|
||||
#endif
|
||||
unsigned ProfilePtr;
|
||||
}
|
||||
|
||||
extern "C" void Old_Profiler_Callback ( UINT, UINT , DWORD, DWORD, DWORD );
|
||||
extern "C" void New_Profiler_Callback (void);
|
||||
extern "C" {
|
||||
extern unsigned ProfileFunctionAddress;
|
||||
}
|
||||
|
||||
unsigned long ProfilerEvent; //Handle for profiler callback
|
||||
unsigned long ProfilerThread; //Handle for profiler thread
|
||||
|
||||
|
||||
HANDLE CCThreadHandle;
|
||||
CONTEXT ThreadContext;
|
||||
|
||||
|
||||
#if (PROFILE_SYSTEM == NEW_PROFILE_SYSTEM)
|
||||
|
||||
/***********************************************************************************************
|
||||
* Thread_Callback -- gets the IP address of our thread and registers it *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: Windows timer callback parms - not used *
|
||||
* *
|
||||
* OUTPUT: Nothing *
|
||||
* *
|
||||
* WARNINGS: None *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/2/96 6:37AM ST : Created *
|
||||
*=============================================================================================*/
|
||||
|
||||
void CALLBACK Thread_Callback (UINT,UINT,DWORD,DWORD,DWORD)
|
||||
{
|
||||
ThreadContext.ContextFlags = VDMCONTEXT_CONTROL;
|
||||
if (!InTimerCallback){
|
||||
GetThreadContext ( CCThreadHandle , &ThreadContext );
|
||||
}else{
|
||||
GetThreadContext (TimerThreadHandle , &ThreadContext);
|
||||
}
|
||||
|
||||
ProfileFunctionAddress = ThreadContext.Eip;
|
||||
New_Profiler_Callback();
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Profile_Thread -- this is the thread our profiler runs in. It just starts off a timer and *
|
||||
* then buggers off into an infinite message loop. We shouldnt get messages *
|
||||
* here as this isnt our primary thread *
|
||||
* *
|
||||
* INPUT: Nothing *
|
||||
* *
|
||||
* OUTPUT: Nothing *
|
||||
* *
|
||||
* WARNINGS: None *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 1/2/96 6:39AM ST : Created *
|
||||
*=============================================================================================*/
|
||||
void Profile_Thread (void)
|
||||
{
|
||||
MSG msg;
|
||||
ProfilerEvent = timeSetEvent (1000/PROFILE_RATE , 1 , Thread_Callback , 0 , TIME_PERIODIC);
|
||||
//ProfilerEvent = timeSetEvent (100 , 1 , Thread_Callback , 0 , TIME_ONESHOT);
|
||||
do {
|
||||
GetMessage(&msg,NULL,0,0);
|
||||
} while(1);
|
||||
}
|
||||
|
||||
#endif //(PROFILE_SYSTEM == OLD_PROFILE_SYSTEM)
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Start_Profiler -- initialises the profiler system and starts sampling *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: Nothing *
|
||||
* *
|
||||
* OUTPUT: Nothing *
|
||||
* *
|
||||
* WARNINGS: There may be a pause when sampling starts as Win95 does some VMM stuff *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/20/95 5:12PM ST : Created *
|
||||
*=============================================================================================*/
|
||||
|
||||
void __cdecl Start_Profiler (void)
|
||||
{
|
||||
#ifdef PROFILE
|
||||
if (!ProfilerEvent){
|
||||
memset (&ProfileList[0],-1,PROFILE_RATE*MAX_PROFILE_TIME*4);
|
||||
}
|
||||
|
||||
Profile_Init();
|
||||
|
||||
if (!ProfilerEvent){
|
||||
|
||||
#if (PROFILE_SYSTEM == OLD_PROFILE_SYSTEM)
|
||||
/*
|
||||
** Old profile system - just set up a timer to monitor the global variable based on
|
||||
** the last place __PRO was called from
|
||||
*/
|
||||
ProfilerEvent = timeSetEvent (1000/PROFILE_RATE , 1 , (void CALLBACK (UINT,UINT,DWORD,DWORD,DWORD))Old_Profiler_Callback , 0 , TIME_PERIODIC);
|
||||
#else
|
||||
/*
|
||||
** New profile system - create a second thread that will do all the profiling
|
||||
** using GetThreadContext
|
||||
*/
|
||||
if ( DuplicateHandle( GetCurrentProcess(), GetCurrentThread() , GetCurrentProcess() ,&CCThreadHandle , 0 , TRUE , DUPLICATE_SAME_ACCESS) ){
|
||||
ProfilerEvent= (unsigned)CreateThread(NULL,2048,(LPTHREAD_START_ROUTINE)&Profile_Thread,NULL,0,&ProfilerThread);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
ProfilerEvent = 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Stop_Profiler -- stops the sampling timer and writes the colledted data to disk *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* INPUT: Nothing *
|
||||
* *
|
||||
* OUTPUT: Nothing *
|
||||
* *
|
||||
* WARNINGS: Writes to file PROFILE.BIN *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/20/95 5:13PM ST : Created *
|
||||
*=============================================================================================*/
|
||||
|
||||
void __cdecl Stop_Profiler (void)
|
||||
{
|
||||
if (ProfilerEvent){
|
||||
|
||||
#if (PROFILE_SYSTEM == OLD_PROFILE_SYSTEM)
|
||||
//
|
||||
// Old system - just remove the timer event
|
||||
//
|
||||
timeKillEvent(ProfilerEvent);
|
||||
#else
|
||||
//
|
||||
// New system - kill the profiling thread
|
||||
//
|
||||
TerminateThread((HANDLE)ProfilerThread,0);
|
||||
#endif
|
||||
|
||||
ProfilerEvent=NULL;
|
||||
|
||||
Profile_End();
|
||||
|
||||
int handle = Open_File ( "profile.bin" , WRITE );
|
||||
if (handle != WW_ERROR){
|
||||
Write_File (handle , &ProfileList[0] , ProfilePtr*4);
|
||||
Close_File (handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user