summaryrefslogtreecommitdiff
path: root/utils/vmpi/vmpi_distribute_tracker.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/vmpi/vmpi_distribute_tracker.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/vmpi/vmpi_distribute_tracker.cpp')
-rw-r--r--utils/vmpi/vmpi_distribute_tracker.cpp579
1 files changed, 579 insertions, 0 deletions
diff --git a/utils/vmpi/vmpi_distribute_tracker.cpp b/utils/vmpi/vmpi_distribute_tracker.cpp
new file mode 100644
index 0000000..9a112fd
--- /dev/null
+++ b/utils/vmpi/vmpi_distribute_tracker.cpp
@@ -0,0 +1,579 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include <windows.h>
+#include <conio.h>
+#include <io.h>
+#include "vmpi.h"
+#include "vmpi_distribute_work.h"
+#include "tier0/platform.h"
+#include "tier0/dbg.h"
+#include "utlvector.h"
+#include "utllinkedlist.h"
+
+
+#define EVENT_TYPE_SEND_WORK_UNIT 0
+#define EVENT_TYPE_WU_STARTED 1
+#define EVENT_TYPE_WU_COMPLETED 2
+
+class CWorkUnitEvent
+{
+public:
+ int m_iEventType; // EVENT_TYPE_ define.
+ int m_iWorker;
+ double m_flTime;
+};
+
+
+class CWorkUnit
+{
+public:
+ CWorkUnit()
+ {
+ m_iWorkerCompleted = -1;
+ }
+
+ int m_iWorkerCompleted; // Which worker completed this work unit (-1 if not done yet).
+
+ CUtlVector<CWorkUnitEvent> m_Events;
+};
+
+
+static CUtlVector<CWorkUnit> g_WorkUnits;
+static double g_flJobStartTime;
+static bool g_bTrackWorkUnitEvents = false;
+
+
+static int CountActiveWorkUnits()
+{
+ int nActive = 0;
+ for ( int i=0; i < g_WorkUnits.Count(); i++ )
+ {
+ if ( g_WorkUnits[i].m_iWorkerCompleted == -1 )
+ ++nActive;
+ }
+ return nActive;
+}
+
+
+// ------------------------------------------------------------------------ //
+// Graphical functions.
+// ------------------------------------------------------------------------ //
+
+static bool g_bUseGraphics = false;
+static HWND g_hWnd = 0;
+
+static int g_LastSizeX = 600, g_LastSizeY = 600;
+
+static COLORREF g_StateColors[] =
+{
+ RGB(50,50,50),
+ RGB(100,0,0),
+ RGB(150,0,0),
+ RGB(0,155,0),
+ RGB(0,255,0),
+ RGB(0,0,150),
+ RGB(0,0,250)
+};
+
+static HANDLE g_hCreateEvent = 0;
+static HANDLE g_hDestroyWindowEvent = 0;
+static HANDLE g_hDestroyWindowCompletedEvent = 0;
+
+static CRITICAL_SECTION g_CS;
+
+class CWUStatus
+{
+public:
+ CWUStatus()
+ {
+ m_iState = 0;
+ memset( &m_Rect, 0, sizeof( m_Rect ) );
+ }
+
+ RECT m_Rect;
+ int m_iState; // 0 = not sent yet
+ // 1 = sent, 2 = sent recently
+ // 3 = done, 4 = done recently
+ // 5 = started, 6 = started recently
+ float m_flTransitionTime;
+};
+CUtlVector<CWUStatus> g_WUStatus;
+int g_nChanges = 0;
+int g_nLastDrawnChanges = -1;
+
+static LRESULT CALLBACK TrackerWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch( uMsg )
+ {
+ case WM_PAINT:
+ {
+ // Do one pass for each color..
+ HBRUSH hStateColors[ARRAYSIZE( g_StateColors )];
+ for ( int i=0; i < ARRAYSIZE( hStateColors ); i++ )
+ hStateColors[i] = CreateSolidBrush( g_StateColors[i] );
+
+ // Copy the WU statuses.
+ CUtlVector<CWUStatus> wuStatus;
+ EnterCriticalSection( &g_CS );
+
+ g_nLastDrawnChanges = g_nChanges;
+ wuStatus.SetSize( g_WUStatus.Count() );
+ memcpy( wuStatus.Base(), g_WUStatus.Base(), wuStatus.Count() * sizeof( wuStatus[0] ) );
+
+ LeaveCriticalSection( &g_CS );
+
+ PAINTSTRUCT ps;
+ HDC hDC = BeginPaint( hwnd, &ps );
+ for ( int iState=0; iState < ARRAYSIZE( hStateColors ); iState++ )
+ {
+ HGDIOBJ hOldObj = SelectObject( hDC, hStateColors[iState] );
+
+ for ( int iWU=0; iWU < wuStatus.Count(); iWU++ )
+ {
+ if ( wuStatus[iWU].m_iState != iState )
+ continue;
+
+ RECT &rc = wuStatus[iWU].m_Rect;
+ Rectangle( hDC, rc.left, rc.top, rc.right, rc.bottom );
+ }
+
+ SelectObject( hDC, hOldObj );
+ DeleteObject( hStateColors[iState] );
+ }
+ EndPaint( hwnd, &ps );
+ }
+ break;
+
+ case WM_SIZE:
+ {
+ int width = LOWORD( lParam );
+ int height = HIWORD( lParam );
+
+ g_LastSizeX = width;
+ g_LastSizeY = height;
+
+ // Figure out the rectangles for everything.
+ int nWorkUnits = g_WUStatus.Count();
+
+ // What is the max width of the grid elements so they will fit in the width and height.
+ int testSize;
+ for ( testSize=20; testSize > 1; testSize-- )
+ {
+ int nX = width / testSize;
+ int nY = height / testSize;
+ if ( nX * nY >= nWorkUnits )
+ break;
+ }
+ static int minTestSize = 3;
+ testSize = max( testSize, minTestSize );
+
+ int xPos=0, yPos=0;
+ for ( int i=0; i < nWorkUnits; i++ )
+ {
+ g_WUStatus[i].m_Rect.left = xPos;
+ g_WUStatus[i].m_Rect.top = yPos;
+ g_WUStatus[i].m_Rect.right = xPos + testSize;
+ g_WUStatus[i].m_Rect.bottom = yPos + testSize;
+
+ xPos += testSize;
+ if ( (xPos+testSize) > width )
+ {
+ yPos += testSize;
+ xPos = 0;
+ }
+ }
+ }
+ break;
+ }
+
+ return DefWindowProc( hwnd, uMsg, wParam, lParam );
+}
+
+static void CheckFlashTimers()
+{
+ double flCurTime = Plat_FloatTime();
+
+ EnterCriticalSection( &g_CS );
+
+ // Check timers for the events that just happened (we show them in a brighter color if they just occurred).
+ for ( int iWU=0; iWU < g_WUStatus.Count(); iWU++ )
+ {
+ CWUStatus &s = g_WUStatus[iWU];
+
+ if ( s.m_iState == 2 || s.m_iState == 4 || s.m_iState == 6 )
+ {
+ if ( flCurTime > s.m_flTransitionTime )
+ {
+ s.m_iState -= 1;
+ ++g_nChanges;
+ }
+ }
+ }
+
+ LeaveCriticalSection( &g_CS );
+}
+
+static DWORD WINAPI ThreadProc( LPVOID lpParameter )
+{
+ // Create the window.
+ const char *pClassName = "VMPI_Tracker";
+
+ // Register the application
+ WNDCLASSEX WndClsEx;
+ WndClsEx.cbSize = sizeof(WNDCLASSEX);
+ WndClsEx.style = CS_HREDRAW | CS_VREDRAW;
+ WndClsEx.lpfnWndProc = TrackerWindowProc;
+ WndClsEx.cbClsExtra = 0;
+ WndClsEx.cbWndExtra = 0;
+ WndClsEx.hIcon = NULL;
+ WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW);
+ WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+ WndClsEx.lpszMenuName = NULL;
+ WndClsEx.lpszClassName = pClassName;
+ WndClsEx.hInstance = (HINSTANCE)GetCurrentProcess();
+ WndClsEx.hIconSm = NULL;
+ RegisterClassEx(&WndClsEx);
+
+ // Create the window.
+ g_hWnd = CreateWindow(
+ pClassName,
+ "VMPI Tracker",
+ WS_OVERLAPPEDWINDOW,
+ 0, 0, g_LastSizeX, g_LastSizeY,
+ NULL, NULL,
+ (HINSTANCE)GetCurrentProcess(),
+ NULL );
+
+ ShowWindow( g_hWnd, SW_SHOW );
+
+ // Tell the main thread we're ready.
+ SetEvent( g_hCreateEvent );
+
+ // Run our main loop.
+ while ( WaitForSingleObject( g_hDestroyWindowEvent, 200 ) != WAIT_OBJECT_0 )
+ {
+ MSG msg;
+ while ( PeekMessage( &msg, g_hWnd, 0, 0, PM_REMOVE ) )
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ CheckFlashTimers();
+
+ if ( g_nChanges != g_nLastDrawnChanges )
+ InvalidateRect( g_hWnd, NULL, FALSE );
+ }
+
+ // Tell the main thread we're done.
+ SetEvent( g_hDestroyWindowCompletedEvent );
+ return 0;
+}
+
+static void Graphical_Start()
+{
+ g_bUseGraphics = VMPI_IsParamUsed( mpi_Graphics );
+ if ( !g_bUseGraphics )
+ return;
+
+ // Setup an event so we'll wait until the window is ready.
+ if ( !g_hCreateEvent )
+ {
+ g_hCreateEvent = CreateEvent( 0, 0, 0, 0 );
+ g_hDestroyWindowEvent = CreateEvent( 0, 0, 0, 0 );
+ g_hDestroyWindowCompletedEvent = CreateEvent( 0, 0, 0, 0 );
+ InitializeCriticalSection( &g_CS );
+ }
+ ResetEvent( g_hCreateEvent );
+ ResetEvent( g_hDestroyWindowCompletedEvent );
+
+ g_WUStatus.SetSize( g_WorkUnits.Count() );
+ for ( int i=0; i < g_WUStatus.Count(); i++ )
+ g_WUStatus[i].m_iState = 0;
+
+ // Setup our thread.
+ CreateThread( NULL, 0, ThreadProc, NULL, 0, NULL );
+
+ // Wait until the event is signaled.
+ WaitForSingleObject( g_hCreateEvent, INFINITE );
+}
+
+static void Graphical_WorkUnitSentToWorker( int iWorkUnit )
+{
+ if ( !g_bUseGraphics )
+ return;
+
+ EnterCriticalSection( &g_CS );
+
+ CWUStatus &s = g_WUStatus[iWorkUnit];
+ if ( s.m_iState != 3 && s.m_iState != 4 && s.m_iState != 5 && s.m_iState != 6 )
+ {
+ s.m_iState = 2;
+ s.m_flTransitionTime = Plat_FloatTime() + 0.1f;
+ ++g_nChanges;
+ }
+
+ LeaveCriticalSection( &g_CS );
+}
+
+static void Graphical_WorkUnitStarted( int iWorkUnit )
+{
+ if ( !g_bUseGraphics )
+ return;
+
+ EnterCriticalSection( &g_CS );
+
+ if ( g_WUStatus[iWorkUnit].m_iState != 3 && g_WUStatus[iWorkUnit].m_iState != 4 )
+ {
+ g_WUStatus[iWorkUnit].m_iState = 6;
+ g_WUStatus[iWorkUnit].m_flTransitionTime = Plat_FloatTime() + 0.1f;
+ ++g_nChanges;
+ }
+
+ LeaveCriticalSection( &g_CS );
+}
+
+static void Graphical_WorkUnitCompleted( int iWorkUnit )
+{
+ if ( !g_bUseGraphics )
+ return;
+
+ EnterCriticalSection( &g_CS );
+ g_WUStatus[iWorkUnit].m_iState = 4;
+ g_WUStatus[iWorkUnit].m_flTransitionTime = Plat_FloatTime() + 0.1f;
+ ++g_nChanges;
+ LeaveCriticalSection( &g_CS );
+}
+
+static void Graphical_End()
+{
+ if ( !g_bUseGraphics )
+ return;
+
+ SetEvent( g_hDestroyWindowEvent );
+ WaitForSingleObject( g_hDestroyWindowCompletedEvent, INFINITE );
+}
+
+
+// ------------------------------------------------------------------------ //
+// Interface functions.
+// ------------------------------------------------------------------------ //
+
+void VMPITracker_Start( int nWorkUnits )
+{
+ g_bTrackWorkUnitEvents = (VMPI_IsParamUsed( mpi_TrackEvents ) || VMPI_IsParamUsed( mpi_Graphics ));
+ g_flJobStartTime = Plat_FloatTime();
+ g_WorkUnits.Purge();
+
+ if ( g_bTrackWorkUnitEvents )
+ {
+ g_WorkUnits.SetSize( nWorkUnits );
+ }
+
+ Graphical_Start();
+}
+
+
+void VMPITracker_WorkUnitSentToWorker( int iWorkUnit, int iWorker )
+{
+ if ( g_bTrackWorkUnitEvents )
+ {
+ CWorkUnitEvent event;
+ event.m_iEventType = EVENT_TYPE_SEND_WORK_UNIT;
+ event.m_iWorker = iWorker;
+ event.m_flTime = Plat_FloatTime();
+ g_WorkUnits[iWorkUnit].m_Events.AddToTail( event );
+ }
+
+ Graphical_WorkUnitSentToWorker( iWorkUnit );
+}
+
+
+void VMPITracker_WorkUnitStarted( int iWorkUnit, int iWorker )
+{
+ if ( g_bTrackWorkUnitEvents )
+ {
+ CWorkUnitEvent event;
+ event.m_iEventType = EVENT_TYPE_WU_STARTED;
+ event.m_iWorker = iWorker;
+ event.m_flTime = Plat_FloatTime();
+ g_WorkUnits[iWorkUnit].m_Events.AddToTail( event );
+ }
+
+ Graphical_WorkUnitStarted( iWorkUnit );
+}
+
+
+void VMPITracker_WorkUnitCompleted( int iWorkUnit, int iWorker )
+{
+ if ( g_bTrackWorkUnitEvents )
+ {
+ CWorkUnitEvent event;
+ event.m_iEventType = EVENT_TYPE_WU_COMPLETED;
+ event.m_iWorker = iWorker;
+ event.m_flTime = Plat_FloatTime();
+ g_WorkUnits[iWorkUnit].m_Events.AddToTail( event );
+ g_WorkUnits[iWorkUnit].m_iWorkerCompleted = iWorker;
+ }
+
+ Graphical_WorkUnitCompleted( iWorkUnit );
+}
+
+
+void VMPITracker_End()
+{
+ g_WorkUnits.Purge();
+ Graphical_End();
+}
+
+
+bool VMPITracker_WriteDebugFile( const char *pFilename )
+{
+ FILE *fp = fopen( pFilename, "wt" );
+ if ( fp )
+ {
+ fprintf( fp, "# work units: %d\n", g_WorkUnits.Count() );
+ fprintf( fp, "# active work units: %d\n", CountActiveWorkUnits() );
+
+ fprintf( fp, "\n" );
+ fprintf( fp, "--- Events ---" );
+ fprintf( fp, "\n" );
+ fprintf( fp, "\n" );
+
+ for ( int i=0; i < g_WorkUnits.Count(); i++ )
+ {
+ CWorkUnit *wu = &g_WorkUnits[i];
+
+ if ( wu->m_iWorkerCompleted != -1 )
+ continue;
+
+ fprintf( fp, " work unit %d\n", i );
+ fprintf( fp, "\n" );
+
+ if ( wu->m_Events.Count() == 0 )
+ {
+ fprintf( fp, " *no events*\n" );
+ }
+ else
+ {
+ for ( int iEvent=0; iEvent < wu->m_Events.Count(); iEvent++ )
+ {
+ CWorkUnitEvent *pEvent = &wu->m_Events[iEvent];
+
+ if ( pEvent->m_iEventType == EVENT_TYPE_WU_STARTED )
+ {
+ fprintf( fp, " started (by worker %s) %.1f seconds ago\n",
+ VMPI_GetMachineName( wu->m_Events[iEvent].m_iWorker ),
+ Plat_FloatTime() - wu->m_Events[iEvent].m_flTime );
+ }
+ else if ( pEvent->m_iEventType == EVENT_TYPE_SEND_WORK_UNIT )
+ {
+ fprintf( fp, " sent (to worker %s) %.1f seconds ago\n",
+ VMPI_GetMachineName( wu->m_Events[iEvent].m_iWorker ),
+ Plat_FloatTime() - wu->m_Events[iEvent].m_flTime );
+ }
+ else if ( pEvent->m_iEventType == EVENT_TYPE_WU_COMPLETED )
+ {
+ fprintf( fp, " completed (by worker %s) %.1f seconds ago\n",
+ VMPI_GetMachineName( wu->m_Events[iEvent].m_iWorker ),
+ Plat_FloatTime() - wu->m_Events[iEvent].m_flTime );
+ }
+ }
+ }
+ fprintf( fp, "\n" );
+ }
+
+ fclose( fp );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void VMPITracker_HandleDebugKeypresses()
+{
+ if ( !g_bTrackWorkUnitEvents )
+ return;
+
+ if ( !kbhit() )
+ return;
+
+ static int iState = 0;
+
+ int key = toupper( getch() );
+ if ( iState == 0 )
+ {
+ if ( key == 'D' )
+ {
+ iState = 1;
+ Warning("\n\n"
+ "----------------------\n"
+ "1. Write debug file (ascending filenames).\n"
+ "2. Write debug file (c:\\vmpi_tracker_0.txt).\n"
+ "3. Invite debug workers (password: 'debugworker').\n"
+ "\n"
+ "0. Exit menu.\n"
+ "----------------------\n"
+ "\n"
+ );
+ }
+ }
+ else if ( iState == 1 )
+ {
+ if ( key == '1' )
+ {
+ iState = 0;
+
+ int nMaxTries = 128;
+ char filename[512];
+ int iFile = 1;
+ for ( iFile; iFile < nMaxTries; iFile++ )
+ {
+ Q_snprintf( filename, sizeof( filename ), "c:\\vmpi_tracker_%d.txt", iFile );
+ if ( _access( filename, 0 ) != 0 )
+ break;
+ }
+ if ( iFile == nMaxTries )
+ {
+ Warning( "** Please delete c:\\vmpi_tracker_*.txt and try again.\n" );
+ }
+ else
+ {
+ if ( VMPITracker_WriteDebugFile( filename ) )
+ Warning( "Wrote %s successfully.\n", filename );
+ else
+ Warning( "Failed to write %s successfully.\n", filename );
+ }
+ }
+ else if ( key == '2' )
+ {
+ iState = 0;
+
+ const char *filename = "c:\\vmpi_tracker_0.txt";
+ if ( VMPITracker_WriteDebugFile( filename ) )
+ Warning( "Wrote %s successfully.\n", filename );
+ else
+ Warning( "Failed to write %s successfully.\n", filename );
+ }
+ else if ( key == '3' )
+ {
+ iState = 0;
+ Warning( "\nInviting debug workers with password 'debugworker'...\nGo ahead and connect them.\n" );
+ VMPI_InviteDebugWorkers();
+ }
+ else if ( key == '0' )
+ {
+ iState = 0;
+ Warning( "\n\nExited menu.\n\n" );
+ }
+ }
+}
+
+