Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1250 lines
28 KiB

//+------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993.
//
// File: procswap.cxx
//
// Contents: Program for measuring task switching performance
// between two windows programs. The program creates
// CTaskSwitch objects...
//
// Each Object can wait on one of three things...
// 1. GetMessage
// 2. MsgWaitForMultipleObjects
// 3. WaitForSingleObject (event)
//
// and when awoken, will signal another Object in one
// of three ways...
// 1. PostMessage
// 2. SendMessage
// 3. SetEvent
//
// These cases can be combined in any manner to obtain
// a maxtrix of possible scenarios.
//
// The CTaskSwitch objects can be in the same process on
// different threads, or in different processes.
//
// Classes: CEvent - event handling class
// CTaskSwitch - main task switch class
//
//
// Functions: WinMain - entry point of process
// ThreadEntry - entry point of spawned threads
// ThreadWndProc - processes windows messages
//
//
// History: 08-Feb-94 Rickhi Created
//
//--------------------------------------------------------------------------
#include <benchmrk.hxx>
#include <tchar.h>
// execution parameter structure
typedef struct tagSExecParms
{
int oloop; // outer loop count
int iloop; // inner loop count
HWND hWndOther; // HWND of other process
HANDLE hEventOther; // Event Handle of other process
WNDPROC pfnWndProc; // ptr to WndProc function
TCHAR szFile[20]; // output file name
TCHAR szWaitEvent[20]; // event name to wait on
TCHAR szSignalEvent[20]; // event name to signal
} SExecParms;
typedef enum tagWAITTYPES
{
WAIT_EVENT = 1,
WAIT_MSGWAITFORMULTIPLE = 2,
WAIT_GETMESSAGE = 3,
WAIT_SYNCHRONOUS = 4
} WAITTYPES;
typedef enum tagSIGNALTYPES
{
SIGNAL_EVENT = 1,
SIGNAL_POSTMESSAGE = 2,
SIGNAL_SENDMESSAGE = 3,
SIGNAL_SYNCHRONOUS = 4
} SIGNALTYPES;
// input names corresponding to the wait types
LPSTR aszWait[] = {"", "event", "msgwait", "getmsg", "sync", NULL};
// input names corresponding to the signal types
LPSTR aszSignal[] = {"", "event", "postmsg", "sendmsg", "sync", NULL};
// Name of window class for dispatching messages.
#define MY_WINDOW_CLASS TEXT("ProcSwapWindowClass")
#define MAX_OLOOP 100
// globals
DWORD g_fFullInfo = 0; // write full info or not
HINSTANCE g_hInst = NULL; // misc windows junk.
ATOM g_MyClass = 0;
UINT g_MyMessage = WM_USER;
// function prototype
LRESULT ThreadWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam);
DWORD ThreadEntry(void *param);
//--------------------------------------------------------------------------
//
// Class: CEvent
//
// Purpose: class for blocking & starting threads.
//
//--------------------------------------------------------------------------
class CEvent
{
public:
CEvent(LPTSTR szName, HRESULT &hr) { Init(szName, hr); }
CEvent(void) {m_hdl = NULL; }
~CEvent() { CloseHandle(m_hdl); }
void Signal(void) { SetEvent(m_hdl); }
void Reset(void) { ; } // ResetEvent(m_hdl); }
void BlockS(void) { WaitForSingleObject(m_hdl, 60000); }
void BlockM(void) { WaitForMultipleObjects(1, &m_hdl, FALSE, 60000); }
HANDLE *GetHdl(void) { return &m_hdl; };
void Init(LPTSTR szName, HRESULT &hr);
private:
HANDLE m_hdl;
};
void CEvent::Init(LPTSTR szName, HRESULT &hr)
{
hr = S_OK;
// first try opening the event
m_hdl = OpenEvent(EVENT_ALL_ACCESS,
FALSE,
szName);
if (m_hdl == NULL)
{
// doesnt exist yet so create it.
m_hdl = CreateEvent(NULL, // security
FALSE, // auto reset
FALSE, // initially not signalled
szName);
if (m_hdl == NULL)
{
_tprintf (TEXT("Error Creating CEvent (%s)\n"), szName);
hr = GetLastError();
}
else
{
_tprintf (TEXT("Created CEvent (%s)\n"), szName);
}
}
else
{
_tprintf (TEXT("Opened CEvent (%s)\n"), szName);
}
}
//--------------------------------------------------------------------------
//
// Class: CTaskSwitch
//
// Purpose: class for timing task switches.
//
//--------------------------------------------------------------------------
class CTaskSwitch
{
public:
CTaskSwitch(LPSTR lpszCmdLine, HRESULT &hr);
~CTaskSwitch(void);
int MainProcessLoop(void);
LRESULT ThreadWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam);
HRESULT SpawnOtherSide(void);
private:
// initialization / cleanup methods
HRESULT ParseCmdLine(LPSTR lpszCmdLine, SExecParms &execp);
HRESULT WindowInitialize(WNDPROC pfnWndProc, HWND &hWnd);
void WindowUninitialize(HWND hWnd);
void CreateOtherParms(void);
void WriteExecParms(void);
void WriteResults(void);
void Help(void);
DWORD GetWaitType(LPSTR pszCmd);
DWORD GetSignalType(LPSTR pszCmd);
DWORD CreateProc(void);
// processing methods
HRESULT SendOrWaitFirstSignal(void);
void ProcessMsgWaitForMultiple(DWORD dwRet);
void ProcessIncommingEvent(void);
void UpdateLoopCounters(void);
void SignalOtherSide(void);
// data
BOOL g_fDone; // when to exit the loop
BOOL g_fKicker; // we kick the other guy
BOOL g_fThreadSwitch; // thread or process switching?
BOOL g_fWaitMultiple; // wait single or multiple
ULONG g_oloop; // outer loop counter
ULONG g_iloop; // inner loop counter
DWORD g_WaitType; // what to wait on
DWORD g_SignalType; // what to signal
// used only for parameter parseing
DWORD g_WaitType1; // what to wait on
DWORD g_SignalType1; // what to signal
DWORD g_WaitType2; // what to wait on
DWORD g_SignalType2; // what to signal
HWND g_hWndOther; // hWnd of other side
HWND g_hWndMe; // my hWnd
CEvent g_WaitEvent; // event to wait on
CEvent g_SignalEvent; // event to signal
ULONG g_time[MAX_OLOOP]; // place to store the timings.
CStopWatch g_timer; // global timer proc 1
SExecParms g_execp; // execution parameters
CTestOutput * g_output; // output log
HRESULT g_hr; // result code
CHAR g_szOtherParms[MAX_PATH]; // parm string for other guy
};
// task switch objects - must be global for ThreadWndProc
CTaskSwitch *g_pTaskSwitch1 = NULL;
CTaskSwitch *g_pTaskSwitch2 = NULL;
//--------------------------------------------------------------------------
//
// WinMain - main entry point of program. May just call ThreadEntry, or
// may spawn another thread in the case of thread switching.
//
//
//--------------------------------------------------------------------------
int WinMain(HINSTANCE hinst, HINSTANCE hPrev, LPSTR lpszCmdLine, int CmdShow)
{
HRESULT hr;
// create the first task switch object for this process
g_pTaskSwitch1 = new CTaskSwitch(lpszCmdLine, hr);
if (hr == S_OK)
{
// spawn a new thread or a new process to do task switching with.
hr = g_pTaskSwitch1->SpawnOtherSide();
if (hr == S_OK)
{
// enter the main processing loop
g_pTaskSwitch1->MainProcessLoop();
}
}
// print the results
delete g_pTaskSwitch1;
return 1;
}
//--------------------------------------------------------------------------
//
// ThreadEntry - main entry point for a thread spawned by CreateThread
// in the case of task switching between threads.
//
// Creates an instance of the CTaskSwitch class and invokes it
// main function.
//
//--------------------------------------------------------------------------
DWORD ThreadEntry(void *param)
{
LPSTR lpszCmdLine = (LPSTR) param;
HRESULT hr;
// create the second task switch object for this process
g_pTaskSwitch2 = new CTaskSwitch(lpszCmdLine, hr);
if (hr == S_OK)
{
// enter the main processing loop
g_pTaskSwitch2->MainProcessLoop();
}
// print the results
delete g_pTaskSwitch2;
return hr;
}
//--------------------------------------------------------------------------
//
// Dipatch to the correct CTaskSwitch object if the message is our
// special message.
//
//--------------------------------------------------------------------------
LRESULT ThreadWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
if (msg == g_MyMessage)
{
// its my special message, go handle it.
// here i have to select which object to dispatch to for the
// multithreaded case. i base that decision on lparam.
if (lparam == 0)
{
// use the first task switch object
return g_pTaskSwitch1->ThreadWndProc(hWnd, msg, wparam, lparam);
}
else
{
// use the second task switch object
return g_pTaskSwitch2->ThreadWndProc(hWnd, msg, wparam, lparam);
}
}
else
{
// let the default window procedure have the message.
return DefWindowProc(hWnd, msg, wparam, lparam);
}
}
//--------------------------------------------------------------------------
//
// Constructor : parse the command line, create the events, create the
// window, and open a log file.
//
//--------------------------------------------------------------------------
CTaskSwitch::CTaskSwitch(LPSTR lpszCmdLine, HRESULT &hr) :
g_fDone(FALSE),
g_fKicker(FALSE),
g_fThreadSwitch(FALSE),
g_fWaitMultiple(FALSE),
g_oloop(10),
g_iloop(100),
g_WaitType(WAIT_EVENT),
g_SignalType(SIGNAL_EVENT),
g_hWndMe(NULL),
g_hWndOther(NULL),
g_output(NULL),
g_hr(S_OK)
{
// parse command line and write the parms to log file.
g_hr = ParseCmdLine(lpszCmdLine, g_execp);
if (g_hr == S_OK)
{
// Create a log file & write execution parameters
g_output = new CTestOutput(g_execp.szFile);
WriteExecParms();
// create the window for this thread
g_hr = WindowInitialize(g_execp.pfnWndProc, g_hWndMe);
if (g_hr == S_OK)
{
// Create the Wait event.
g_WaitEvent.Init(g_execp.szWaitEvent, g_hr);
if (g_hr == S_OK)
{
// Create the Signal event.
g_SignalEvent.Init(g_execp.szSignalEvent, g_hr);
if (g_hr == S_OK)
{
// create paramters to send to other side.
CreateOtherParms();
}
}
}
}
// return the results
hr = g_hr;
}
//--------------------------------------------------------------------------
//
// Desructor
//
//--------------------------------------------------------------------------
CTaskSwitch::~CTaskSwitch(void)
{
// write the results
WriteResults();
// cleanup window registration
WindowUninitialize(g_hWndMe);
// close the log file
delete g_output;
}
//--------------------------------------------------------------------------
//
// Spawns either another process or another thread to perform the task
// switching with.
//
//--------------------------------------------------------------------------
HRESULT CTaskSwitch::SpawnOtherSide(void)
{
if (g_fKicker)
{
// i'm already the second entry, dont spawn anything.
// sleep for a bit to make sure both sides are ready
// when i kick things off.
Sleep(1000);
return S_OK;
}
if (g_fThreadSwitch)
{
// spawn a thread
HANDLE hdl;
DWORD dwId;
hdl = CreateThread(NULL, // default security
0, // default stack size
ThreadEntry, // entry point
g_szOtherParms, // command line parms
0, // flags
&dwId); // threadid
if (hdl)
{
// dont need the handle
CloseHandle(hdl);
}
else
{
// what went wrong?
return GetLastError();
}
}
else
{
// spawn a process
DWORD dwRet = CreateProc();
if (dwRet != S_OK)
{
return dwRet;
}
}
return S_OK;
}
//--------------------------------------------------------------------------
//
// MainProcessLoop - does the main wait & process the event
//
//--------------------------------------------------------------------------
int CTaskSwitch::MainProcessLoop(void)
{
MSG msg;
DWORD dwRet;
// Send, or wait on, the first signal.
SendOrWaitFirstSignal();
// Reset the timer and enter the main loop.
g_timer.Reset();
// wait loop - based on the type of event we should receive, we
// wait here until such an event occurs. Then we send a signal
// to the other side based on what it expects from us.
while (!g_fDone)
{
switch (g_WaitType)
{
case WAIT_MSGWAITFORMULTIPLE:
// wait here for a message or an event to be signalled
dwRet = MsgWaitForMultipleObjects(1,
g_WaitEvent.GetHdl(),
FALSE,
600000,
QS_ALLINPUT);
// Dispatch to ThreadWndProc if a message, or
// to ProcessEvent if an event was signalled
ProcessMsgWaitForMultiple(dwRet);
break;
case WAIT_GETMESSAGE:
// wait for a windows message
if (GetMessage(&msg, NULL, 0, 0))
{
// dispatches to my ThreadWndProc
DispatchMessage(&msg);
}
break;
case WAIT_EVENT:
// wait for the event to be signalled
if (g_fWaitMultiple)
g_WaitEvent.BlockM();
else
g_WaitEvent.BlockS();
// process the event
ProcessIncommingEvent();
break;
case WAIT_SYNCHRONOUS:
// we have a synchronous singal to the other side, so there is
// nothing to wait on, we will just go make another synchronous
// call. this is valid only if the g_SignalType is
// SIGNAL_SENDMESSAGE.
ProcessIncommingEvent();
break;
default:
// unknown event
break;
}
} // while
return msg.wParam; // Return value from PostQuitMessage
}
//--------------------------------------------------------------------------
//
// processes a wakeup from MsgWaitForMultiple. Determines if the event was
// a message arrival (in which case it Peeks it and Dispatches it, or if it
// was an event signalled, in which case it calls the event handler.
//
//--------------------------------------------------------------------------
void CTaskSwitch::ProcessMsgWaitForMultiple(DWORD dwRet)
{
MSG msg;
if (dwRet == WAIT_OBJECT_0)
{
// our event got signalled, update the counters
ProcessIncommingEvent();
}
else if (dwRet == WAIT_OBJECT_0 + 1)
{
// some windows message was received. dispatch it.
if (PeekMessage(&msg, g_hWndMe, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
}
}
else
{
// our event timed out or our event was abandoned or
// an error occurred.
g_fDone = TRUE;
}
}
//--------------------------------------------------------------------------
//
// processes an incomming event. Just updates the counters and
// signals the other side.
//
//--------------------------------------------------------------------------
void CTaskSwitch::ProcessIncommingEvent(void)
{
// update the loop counters
UpdateLoopCounters();
// Signal the other side
SignalOtherSide();
}
//--------------------------------------------------------------------------
//
// process the incomming message
//
//--------------------------------------------------------------------------
LRESULT CTaskSwitch::ThreadWndProc(HWND hWnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
// save the callers hWnd
g_hWndOther = (HWND) wparam;
// process as usual
ProcessIncommingEvent();
return 0;
}
//--------------------------------------------------------------------------
//
// updates the global loop counters, reseting the time when the inner
// loop counter expires, and setting the fDone when the outer and inner
// loop counters expire.
//
//--------------------------------------------------------------------------
void CTaskSwitch::UpdateLoopCounters(void)
{
if (g_iloop == 0)
{
// get time for latest outer loop
g_time[g_oloop] = g_timer.Read();
if (g_oloop == 0)
{
// that was the last outerloop, we're done.
g_fDone = TRUE;
}
else
{
// update the counters
g_iloop = g_execp.iloop;
--g_oloop;
// restart the timer
g_timer.Reset();
}
}
else
{
// just update the inner loop count
--g_iloop;
}
}
//--------------------------------------------------------------------------
//
// signals the other process or thread according to the SendType (either
// signals an event or posts a message).
//
//--------------------------------------------------------------------------
void CTaskSwitch::SignalOtherSide(void)
{
switch (g_SignalType)
{
case SIGNAL_EVENT:
// signal the other sides event
g_SignalEvent.Signal();
break;
case SIGNAL_POSTMESSAGE:
// post a message to the other sides window handle.
// lparam tells ThreadWndProc which object to dispatch to, either
// g_pTaskSwitch1 or g_pTaskSwitch2. We only go to 2 if we are
// doing thread switches AND the poster is not the kicker.
PostMessage(g_hWndOther,
g_MyMessage,
(WPARAM)g_hWndMe,
(g_fThreadSwitch && !g_fKicker));
break;
case SIGNAL_SENDMESSAGE:
// send a message to the other side. this is a synchronous
// event. see comment in PostMessage above regarding lparam.
SendMessage(g_hWndOther,
g_MyMessage,
(WPARAM)g_hWndMe,
(g_fThreadSwitch && !g_fKicker));
break;
case SIGNAL_SYNCHRONOUS:
// the event we received is a synchronous event. there is no need
// to do anything to wake the other side.
break;
default:
// unknown signal type
break;
}
}
//--------------------------------------------------------------------------
//
// signals the other process or thread that it can begin the test. this
// avoids timings skewed due to process startup latency.
//
//--------------------------------------------------------------------------
HRESULT CTaskSwitch::SendOrWaitFirstSignal(void)
{
if (g_fKicker)
{
// send a signal to drop the otherside into its wait loop, and
// then call SignalOtherSide to start the cycle, kicking the
// other side out of his first wait.
printf ("Initial Signal to Other Side\n");
g_SignalEvent.Signal();
SignalOtherSide();
}
else
{
printf ("Waiting for Signal From Other Side\n");
g_WaitEvent.BlockS();
}
return S_OK;
}
//--------------------------------------------------------------------------
//
// initializes the window with the specified window proc.
//
//--------------------------------------------------------------------------
HRESULT CTaskSwitch::WindowInitialize(WNDPROC pfnWndProc, HWND &hWnd)
{
if (!g_MyMessage)
{
// Register my message type
g_MyMessage = RegisterWindowMessage(
TEXT("Component Object Model Remote Request Arrival") );
}
if (!g_MyClass)
{
// Register my window class.
WNDCLASS wcls;
wcls.style = 0;
wcls.lpfnWndProc = pfnWndProc;
wcls.cbClsExtra = 0;
wcls.cbWndExtra = 0;
wcls.hInstance = g_hInst;
wcls.hIcon = NULL;
wcls.hCursor = NULL;
wcls.hbrBackground = (HBRUSH) COLOR_BACKGROUND + 1;
wcls.lpszMenuName = NULL;
wcls.lpszClassName = MY_WINDOW_CLASS;
g_MyClass = RegisterClass( &wcls );
}
if (g_MyClass)
{
// Create a hidden window.
hWnd = CreateWindowEx( 0,
(LPCTSTR) g_MyClass,
TEXT("Task Switcher"),
WS_DISABLED,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
g_hInst,
NULL );
if (hWnd)
{
printf ("Created Window with hWnd %x\n", hWnd);
return S_OK;
}
}
return E_OUTOFMEMORY;
}
//--------------------------------------------------------------------------
//
// destroys the window and unregisters the class.
//
//--------------------------------------------------------------------------
void CTaskSwitch::WindowUninitialize(HWND hWnd)
{
if (hWnd != NULL)
{
DestroyWindow(hWnd);
}
if (g_MyClass != 0)
{
UnregisterClass(MY_WINDOW_CLASS, g_hInst);
}
}
//--------------------------------------------------------------------------
//
// parses the command line and returns the execution parameters
//
//--------------------------------------------------------------------------
HRESULT CTaskSwitch::ParseCmdLine(LPSTR lpszCmdLine, SExecParms &execp)
{
BOOL fFile = FALSE;
// set the default values for execution parameters.
execp.oloop = 10;
execp.iloop = 100;
execp.hWndOther = NULL;
execp.pfnWndProc = ::ThreadWndProc;
// check the input parameters
LPSTR pszCmd = lpszCmdLine;
LPSTR pszCmdNext = NULL;
while (pszCmd)
{
pszCmdNext = strchr(pszCmd, ' ');
if (pszCmdNext)
{
*pszCmdNext = '\0';
pszCmdNext++;
}
// check for outer loop count
if (!_strnicmp(pszCmd, "/o:", 3))
{
execp.oloop = atoi (pszCmd+3);
if (execp.oloop > MAX_OLOOP)
execp.oloop = MAX_OLOOP;
}
// check for inner loop count
else if (!_strnicmp(pszCmd, "/i:", 3))
{
execp.iloop = atoi (pszCmd+3);
if (execp.iloop < 1)
execp.iloop = 1;
}
// check for window handle
else if (!_strnicmp(pszCmd, "/hwnd:", 6))
{
execp.hWndOther = (HWND) atoi (pszCmd+6);
}
// check for waiter or Kicker
else if (!_strnicmp(pszCmd, "/k", 2))
{
g_fKicker = TRUE;
}
// check for thread or process switch
else if (!_strnicmp(pszCmd, "/p", 2))
{
g_fThreadSwitch = FALSE;
}
// check for thread or process switch
else if (!_strnicmp(pszCmd, "/t", 2))
{
g_fThreadSwitch = TRUE;
}
// check for wait single or multiple
else if (!_strnicmp(pszCmd, "/m", 2))
{
g_fWaitMultiple = TRUE;
}
// check for wait event name
else if (!_strnicmp(pszCmd, "/e1:", 4))
{
#ifdef UNICODE
mbstowcs(execp.szWaitEvent, pszCmd+4, strlen(pszCmd+4)+1);
#else
strcpy(execp.szWaitEvent, pszCmd+4);
#endif
}
// check for signal event name
else if (!_strnicmp(pszCmd, "/e2:", 4))
{
#ifdef UNICODE
mbstowcs(execp.szSignalEvent, pszCmd+4, strlen(pszCmd+4)+1);
#else
strcpy(execp.szSignalEvent, pszCmd+4);
#endif
}
// check for output file name
else if (!_strnicmp(pszCmd, "/f:", 3))
{
fFile = TRUE;
#ifdef UNICODE
mbstowcs(execp.szFile, pszCmd+3, strlen(pszCmd+3)+1);
#else
strcpy(execp.szFile, pszCmd+3);
#endif
}
// check for wait type
else if (!_strnicmp(pszCmd, "/w1:", 4))
{
g_WaitType1 = GetWaitType(pszCmd+4);
}
else if (!_strnicmp(pszCmd, "/w2:", 4))
{
g_WaitType2 = GetWaitType(pszCmd+4);
}
// check for signal type
else if (!_strnicmp(pszCmd, "/s1:", 4))
{
g_SignalType1 = GetSignalType(pszCmd+4);
}
else if (!_strnicmp(pszCmd, "/s2:", 4))
{
g_SignalType2 = GetSignalType(pszCmd+4);
}
// check for help request
else if ((!_strnicmp(pszCmd, "/?", 2)) || (!_strnicmp(pszCmd, "/h", 2)))
{
Help();
return -1;
}
pszCmd = pszCmdNext;
}
g_iloop = execp.iloop;
g_oloop = execp.iloop;
g_hWndOther = execp.hWndOther;
if (g_fKicker)
{
g_WaitType = g_WaitType2;
g_SignalType = g_SignalType2;
if (!fFile)
_tcscpy(execp.szFile, TEXT("kicker"));
}
else
{
g_WaitType = g_WaitType1;
g_SignalType = g_SignalType1;
if (!fFile)
_tcscpy(execp.szFile, TEXT("waiter"));
}
return S_OK;
}
DWORD CTaskSwitch::GetWaitType(LPSTR pszCmd)
{
ULONG i=0;
while (aszWait[++i]) // slot 0 is not used
{
if (!_stricmp(pszCmd, aszWait[i]))
return i;
}
Help();
return 0;
}
DWORD CTaskSwitch::GetSignalType(LPSTR pszCmd)
{
ULONG i=0;
while (aszSignal[++i]) // slot 0 is not used
{
if (!_stricmp(pszCmd, aszSignal[i]))
return i;
}
Help();
return 0;
}
//--------------------------------------------------------------------------
//
// creates the command line parameters for the other guy
//
//--------------------------------------------------------------------------
void CTaskSwitch::CreateOtherParms(void)
{
// write the formatted parms to the parm string
sprintf(g_szOtherParms, "/k %s %s /i:%d /o:%d /hWnd:%ld "
"/e1:%hs /e2:%hs /w1:%s /s1:%s /w2:%s /s2:%s",
(g_fThreadSwitch) ? "/t" : "/p",
(g_fWaitMultiple) ? "/m" : " ",
g_execp.iloop, // same loop counts as me
g_execp.oloop,
g_hWndMe, // posts to my window
g_execp.szSignalEvent, // it waits on my signal event
g_execp.szWaitEvent, // it signals my wait event
aszWait[g_WaitType1], // signal what i wait on
aszSignal[g_SignalType1], // wait on what i signal
aszWait[g_WaitType2], // signal what i wait on
aszSignal[g_SignalType2]); // wait on what i signal
}
//--------------------------------------------------------------------------
//
// writes the execution parameters to a log file.
//
//--------------------------------------------------------------------------
void CTaskSwitch::WriteExecParms()
{
// write the run parameters to the output file
g_output->WriteString(TEXT("Using Parametes:\n"));
g_output->WriteResult(TEXT("\tInner Loop Count = "), g_execp.iloop);
g_output->WriteResult(TEXT("\tOuter Loop Count = "), g_execp.oloop);
g_output->WriteString(TEXT("\n\n"));
// flush to avoid disk io during the test
g_output->Flush();
}
//--------------------------------------------------------------------------
//
// writes the results to a log file.
//
//--------------------------------------------------------------------------
void CTaskSwitch::WriteResults(void)
{
if (g_hr == S_OK)
{
// compute the averages
ULONG tTotal = 0;
// skip the first & last value as they are sometimes skewed
for (int i=0; i<g_execp.oloop; i++)
{
tTotal += g_time[i];
}
// compute average for 1 call/response
tTotal /= (g_execp.oloop * g_execp.iloop);
// display the results
g_output->WriteResults(TEXT("Times "), g_execp.oloop, g_time);
g_output->WriteResult(TEXT("\nAverage "), tTotal);
}
}
//--------------------------------------------------------------------------
//
// writes the help info to the screen
//
//--------------------------------------------------------------------------
void CTaskSwitch::Help()
{
printf ("msgtask\n");
printf ("\t/o:<nnn> - outer loop count def 10\n");
printf ("\t/i:<nnn> - inner loop count def 100\n");
printf ("\t/f:<name> - name of output file. def [kick | wait]\n");
printf ("\t/w1:<event|getmsg|msgwait> - what to wait on\n");
printf ("\t/s1:<event|postmsg> - what to signal\n");
printf ("\t/w2:<event|getmsg|msgwait> - what to wait on\n");
printf ("\t/s2:<event|postmsg> - what to signal\n");
printf ("\t/e1:<name> - name of wait event\n");
printf ("\t/e2:<name> - name of signal event\n");
printf ("\t/k - kicker (as opposed to waiter)\n");
printf ("\t/t - use thread switching\n");
printf ("\t/p - use process switching\n");
printf ("\t/m - use WaitMultiple vs WaitSingle\n");
printf ("\t/hWnd:<nnnn> - window handle of other side\n");
printf ("\n");
printf ("timings are given for the inner loop count calls\n");
return;
}
//--------------------------------------------------------------------------
//
// creates a process
//
//--------------------------------------------------------------------------
DWORD CTaskSwitch::CreateProc(void)
{
// create the command line
TCHAR szCmdLine[256];
_stprintf(szCmdLine, TEXT("ntsd procswap %hs"), g_szOtherParms);
// build the win32 startup info structure
STARTUPINFO startupinfo;
startupinfo.cb = sizeof(STARTUPINFO);
startupinfo.lpReserved = NULL;
startupinfo.lpDesktop = NULL;
startupinfo.lpTitle = TEXT("Task Switcher");
startupinfo.dwX = 40;
startupinfo.dwY = 40;
startupinfo.dwXSize = 80;
startupinfo.dwYSize = 40;
startupinfo.dwFlags = 0;
startupinfo.wShowWindow = SW_SHOWNORMAL;
startupinfo.cbReserved2 = 0;
startupinfo.lpReserved2 = NULL;
PROCESS_INFORMATION ProcInfo;
BOOL fRslt = CreateProcess(NULL, // app name
szCmdLine, // command line
NULL, // lpsaProcess
NULL, // lpsaThread
FALSE, // inherit handles
CREATE_NEW_CONSOLE,// creation flags
NULL, // lpEnvironment
NULL, // curr Dir
&startupinfo, // Startup Info
&ProcInfo); // process info
if (fRslt)
{
// we dont need the handles
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);
printf ("Created Process (%ws) pid=%x\n", szCmdLine, ProcInfo.dwProcessId);
return S_OK;
}
else
{
// what went wrong?
DWORD dwRet = GetLastError();
printf ("CreateProcess (%ws) failed %x\n", szCmdLine, dwRet);
return dwRet;
}
}