//------------------------------------------------------------------------ // // File: shell\themes\test\ctlperf\Perflog.cpp // // Contents: Implementation of the Timing and logging class. // // Classes: CPerfLog // //------------------------------------------------------------------------ #include "stdafx.h" #include "PerfLog.h" //+----------------------------------------------------------------------- // // Member: CPerfLog::CPerfLog // // Synopsis: Constructor // //------------------------------------------------------------------------ CPerfLog::CPerfLog() { ::QueryPerformanceFrequency( (LARGE_INTEGER*) &m_liFreq); m_szPass1[0] = _T('\0'); m_szPass2[0] = _T('\0'); m_bLogging = false; m_nFramePaintTime = 0; m_nFrameResizeTime = 0; m_nFrameResizeAndPaintTime = 0; m_bFrame = false; m_bTwoPasses = false; m_rgnResults1 = NULL; m_rgnResults2 = NULL; m_rgszResults = NULL; m_cnResults1 = 0; m_cnResults2 = 0; m_cszResults = 0; m_bFirstPass = true; m_flLogFile = NULL; m_bNumberOnly = false; } //+----------------------------------------------------------------------- // // Member: CPerfLog::~CPerfLog // // Synopsis: Destructor // //------------------------------------------------------------------------ CPerfLog::~CPerfLog() { StopLogging(); // Just in case the caller didn't call it } //+----------------------------------------------------------------------- // // Member: CPerfLog::StartLoggingOnePass // // Synopsis: Initialization method when loggin one pass // // Arguments: szFileName Name of the log file // hWndStatusBar Handle to a status bar window to receive info // szPass Name of the test // //------------------------------------------------------------------------ void CPerfLog::StartLoggingOnePass(LPCTSTR szFileName, HWND hWndStatusBar, LPCTSTR szPass) { if (m_bLogging) { StopLogging(); } if (m_liFreq == 0) // We can't do anything without it { m_bLogging = false; return; } if (szFileName) { _tcscpy(m_szFileName, szFileName); } if(szPass) { _tcscpy(m_szPass1, szPass); } m_flLogFile = ::_wfopen(szFileName, _T("w")); ATLASSERT(m_flLogFile); if(m_flLogFile != NULL) { m_hWndStatusBar = hWndStatusBar; m_nFramePaintTime = 0; m_nFrameResizeTime = 0; m_nFrameResizeAndPaintTime = 0; m_bLogging = true; } } //+----------------------------------------------------------------------- // // Member: CPerfLog::StopLogging // // Synopsis: Close and cleanup // //------------------------------------------------------------------------ void CPerfLog::StopLogging() { if (m_flLogFile && ::ftell(m_flLogFile) != -1) { ::fflush(m_flLogFile); ::fclose(m_flLogFile); m_flLogFile = NULL; } if (m_rgnResults1) { free(m_rgnResults1); m_rgnResults1 = NULL; m_cnResults1 = 0; } if (m_rgnResults2) { free(m_rgnResults2); m_rgnResults2 = NULL; m_cnResults2 = 0; } if (m_cszResults) { for (UINT i = 0; i < m_cszResults; i++) free(m_rgszResults[i]); free(m_rgszResults); m_rgszResults = NULL; m_cszResults = 0; } m_bLogging = false; } //+----------------------------------------------------------------------- // // Member: CPerfLog::StartLoggingTwoPasses // // Synopsis: Initialization method when loggin two passes // // Arguments: szFileName Name of the log file // hWndStatusBar Handle to a status bar window to receive info // szPass1 Name of the first test // szPass2 Name of the second test // //------------------------------------------------------------------------ void CPerfLog::StartLoggingTwoPasses(LPCTSTR szFileName, HWND hWndStatusBar, LPCTSTR szPass1, LPCTSTR szPass2) { m_bTwoPasses = true; StartLoggingOnePass(szFileName, hWndStatusBar, NULL); // Reuse main initialization (dirty) if (szPass1) { _tcscpy(m_szPass1, szPass1); } if (szPass2) { _tcscpy(m_szPass2, szPass2); } } //+----------------------------------------------------------------------- // // Member: CPerfLog::StopLoggingPass1 // // Synopsis: For parity, does nothing // //------------------------------------------------------------------------ void CPerfLog::StopLoggingPass1() { } //+----------------------------------------------------------------------- // // Member: CPerfLog::StartLoggingPass2 // // Synopsis: Log pass 2 // //------------------------------------------------------------------------ void CPerfLog::StartLoggingPass2() { // Reset variables from pass 1 m_nFramePaintTime = 0; m_nFrameResizeTime = 0; m_nFrameResizeAndPaintTime = 0; m_bFirstPass = false; } //+----------------------------------------------------------------------- // // Member: CPerfLog::StopLoggingPass2 // // Synopsis: Close pass 2, output log and cleanup // //------------------------------------------------------------------------ void CPerfLog::StopLoggingPass2() { UINT iResults2 = 0; UINT iszResults1 = 0; for (UINT iResults1 = 0; iResults1 < m_cnResults1; iResults1++) { if (m_rgnResults1[iResults1] == -1) // This is a string { fputws(m_rgszResults[iszResults1++], m_flLogFile); } else // Two results to display on the same line { if (m_rgnResults1[iResults1]) { // just remvoed one \t so that slow colum would line up. swprintf(m_szBuf, _T("%u\t\t%u\t%.2f\n"), m_rgnResults1[iResults1], m_rgnResults2[iResults2], (100.0f * float(m_rgnResults2[iResults2]) / float(m_rgnResults1[iResults1])) - 100.0f); } else { swprintf(m_szBuf, _T("%u\t\t%u\t\t0\n"), m_rgnResults1[iResults1], m_rgnResults2[iResults2]); } iResults2++; fputws(m_szBuf, m_flLogFile); } } StopLogging(); } //+----------------------------------------------------------------------- // // Member: CPerfLog::LogString // // Synopsis: Stores the string in memory // // Arguments: sz String to log // //------------------------------------------------------------------------ void CPerfLog::LogString(LPCTSTR sz) { if (!m_bTwoPasses) { fputws(sz, m_flLogFile); } else if (m_bFirstPass) { m_cszResults++; m_rgszResults = (LPTSTR*) realloc(m_rgszResults, m_cszResults * sizeof(LPTSTR)); m_rgszResults[m_cszResults - 1] = _wcsdup(sz); m_cnResults1++; m_rgnResults1 = (UINT*) realloc(m_rgnResults1, m_cnResults1 * sizeof(UINT)); // Since -1 is an illegal value for the results, we use it to mark a string m_rgnResults1[m_cnResults1 - 1] = -1; } } //+----------------------------------------------------------------------- // // Member: CPerfLog::OpenLoggingClass // // Synopsis: Start timing a new control class name for the following timing // // Arguments: szClassName Name of class (for logging only) // //------------------------------------------------------------------------ void CPerfLog::OpenLoggingClass(LPCTSTR szClassName) { if (!m_bLogging) { return; } ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L); ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM) szClassName); // Class header in the file if (m_bTwoPasses) { // added number only check if(m_bNumberOnly) { swprintf(m_szBuf, _T("%.12s\t%s\t%% Slower\n"), m_szPass1, m_szPass2); } else { swprintf(m_szBuf, _T("%-23s\t%.12s\t%s\t%% Slower\n"), szClassName, m_szPass1, m_szPass2); } } else { // added number only check if(m_bNumberOnly) { swprintf(m_szBuf, _T("%-23s\n"), szClassName); } else { swprintf(m_szBuf, _T("%-23s\t%s\n"), szClassName, m_szPass1); } } LogString(m_szBuf); if (!m_bFrame && !_tcsicmp(szClassName, kszFrameWnd)) { m_bFrame = true; } else { m_bFrame = false; } } //+----------------------------------------------------------------------- // // Member: CPerfLog::CloseLoggingClass // // Synopsis: Finished with this class // //------------------------------------------------------------------------ void CPerfLog::CloseLoggingClass() { if (!m_bLogging) { return; } LogString(_T("\n")); ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM) _T("")); } //+----------------------------------------------------------------------- // // Member: CPerfLog::StartCreate // // Synopsis: Beginning timing creation test // // Arguments: cCtl Number of controls being created (for logging) // //------------------------------------------------------------------------ void CPerfLog::StartCreate(UINT cCtl) { if (!m_bLogging) { return; } // added number only check if(!m_bNumberOnly) { swprintf(m_szBuf, _T("Creation(x%d)\t\t"), cCtl); LogString(m_szBuf); } ::QueryPerformanceCounter( (LARGE_INTEGER*) &m_liStart); } //+----------------------------------------------------------------------- // // Member: CPerfLog::StopCreate // // Synopsis: Finished timing creation test // //------------------------------------------------------------------------ void CPerfLog::StopCreate() { if (!m_bLogging) { return; } ::QueryPerformanceCounter( (LARGE_INTEGER*) &m_liEnd); OutputData(); } //+----------------------------------------------------------------------- // // Member: CPerfLog::StartPaint // // Synopsis: Beginning timing painting test // // Arguments: nTimes Number of loops executed (for logging) // //------------------------------------------------------------------------ void CPerfLog::StartPaint(UINT nTimes) { if (!m_bLogging) { return; } // added number only check if(!m_bNumberOnly) { swprintf(m_szBuf, _T("Paint(x%d)\t\t"), nTimes); LogString(m_szBuf); } ::QueryPerformanceCounter( (LARGE_INTEGER*) &m_liStart); } //+----------------------------------------------------------------------- // // Member: CPerfLog::StopPaint // // Synopsis: Finished timing painting test // //------------------------------------------------------------------------ void CPerfLog::StopPaint() { if (!m_bLogging) { return; } ::QueryPerformanceCounter( (LARGE_INTEGER*) &m_liEnd); if (m_nFramePaintTime > 0) { m_liEnd -= m_nFramePaintTime; } OutputData(); if (m_bFrame) { ATLASSERT(m_nFramePaintTime == 0); m_nFramePaintTime = UINT(m_liEnd - m_liStart); } } //+----------------------------------------------------------------------- // // Member: CPerfLog::StartResize // // Synopsis: Beginning timing resizing test // // Arguments: nTimes Number of loops executed (for logging) // //------------------------------------------------------------------------ void CPerfLog::StartResize(UINT nTimes) { if (!m_bLogging) { return; } // added number only check if(!m_bNumberOnly) { swprintf(m_szBuf, _T("Resize(x%d)\t\t"), nTimes); LogString(m_szBuf); } ::QueryPerformanceCounter( (LARGE_INTEGER*) &m_liStart); } //+----------------------------------------------------------------------- // // Member: CPerfLog::StopResize // // Synopsis: Finished timing resizing test // //------------------------------------------------------------------------ void CPerfLog::StopResize() { if (!m_bLogging) { return; } ::QueryPerformanceCounter( (LARGE_INTEGER*) &m_liEnd); if (m_nFrameResizeTime > 0) { m_liEnd -= m_nFrameResizeTime; } OutputData(); if (m_bFrame) { ATLASSERT(m_nFrameResizeTime == 0); m_nFrameResizeTime = UINT(m_liEnd - m_liStart); } } //+----------------------------------------------------------------------- // // Member: CPerfLog::StartResizeAndPaint // // Synopsis: Beginning timing resizing with painting test // // Arguments: nTimes Number of loops executed (for logging) // //------------------------------------------------------------------------ void CPerfLog::StartResizeAndPaint(UINT nTimes) { if (!m_bLogging) { return; } // added number only check if(!m_bNumberOnly) { swprintf(m_szBuf, _T("Resize and paint(x%d)\t"), nTimes); LogString(m_szBuf); } ::QueryPerformanceCounter( (LARGE_INTEGER*) &m_liStart); } //+----------------------------------------------------------------------- // // Member: CPerfLog::StopResizeAndPaint // // Synopsis: Finished timing resizing with painting test // //------------------------------------------------------------------------ void CPerfLog::StopResizeAndPaint() { if (!m_bLogging) { return; } ::QueryPerformanceCounter( (LARGE_INTEGER*) &m_liEnd); if (m_nFrameResizeAndPaintTime > 0) { m_liEnd -= m_nFrameResizeAndPaintTime; } OutputData(); if (m_bFrame) { ATLASSERT(m_nFrameResizeAndPaintTime == 0); m_nFrameResizeAndPaintTime = UINT(m_liEnd - m_liStart); } } //+----------------------------------------------------------------------- // // Member: CPerfLog::OutputData // // Synopsis: Stores the data in one of the buffers // //------------------------------------------------------------------------ void CPerfLog::OutputData() { if (m_liEnd < m_liStart) // In case nLoops is low, it can happen { m_liEnd = m_liStart; } UINT nData = UINT((1000.0 * double(m_liEnd - m_liStart)) / double(m_liFreq)); if (!m_bTwoPasses) { fwprintf(m_flLogFile, _T("%u\n"), nData); } else { if (m_bFirstPass) { m_cnResults1++; m_rgnResults1 = (UINT*) realloc(m_rgnResults1, m_cnResults1 * sizeof(UINT)); m_rgnResults1[m_cnResults1 - 1] = nData; } else { m_cnResults2++; m_rgnResults2 = (UINT*) realloc(m_rgnResults2, m_cnResults2 * sizeof(UINT)); m_rgnResults2[m_cnResults2 - 1] = nData; } } } //+----------------------------------------------------------------------- // // Member: CPerfLog::SetOutputType // // Synopsis: Stores the output type (numbers only) for use later // //------------------------------------------------------------------------ void CPerfLog::SetOutputType(LPTSTR szNumberOnly) { if(!_tcsicmp(szNumberOnly, _T("true"))) { m_bNumberOnly = true; } }