// // Driver Verifier UI // Copyright (c) Microsoft Corporation, 1999 // // // // module: GCntPage.cpp // author: DMihai // created: 11/1/00 // // Description: // #include "stdafx.h" #include "verifier.h" #include "GCntPage.h" #include "VrfUtil.h" #include "VGlobal.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // // Timer ID // #define REFRESH_TIMER_ID 0x1234 // // Help IDs // static DWORD MyHelpIds[] = { IDC_GLOBC_LIST, IDH_DV_GlobalCounters, 0, 0 }; ///////////////////////////////////////////////////////////////////////////// // CGlobalCountPage property page IMPLEMENT_DYNCREATE(CGlobalCountPage, CVerifierPropertyPage) CGlobalCountPage::CGlobalCountPage() : CVerifierPropertyPage(CGlobalCountPage::IDD) { //{{AFX_DATA_INIT(CGlobalCountPage) //}}AFX_DATA_INIT m_nSortColumnIndex = 0; m_bAscendSortName = FALSE; m_bAscendSortValue = FALSE; m_uTimerHandler = 0; m_pParentSheet = NULL; } CGlobalCountPage::~CGlobalCountPage() { } void CGlobalCountPage::DoDataExchange(CDataExchange* pDX) { static BOOL bShownPoolCoverageWarning = FALSE; if( ! pDX->m_bSaveAndValidate ) { // // Query the kernel // VrfGetRuntimeVerifierData( &m_RuntimeVerifierData ); if( FALSE == bShownPoolCoverageWarning ) { bShownPoolCoverageWarning = CheckAndShowPoolCoverageWarning(); } } CVerifierPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CGlobalCountPage) DDX_Control(pDX, IDC_GLOBC_LIST, m_CountersList); DDX_Control(pDX, IDC_GLOBC_NEXT_DESCR_STATIC, m_NextDescription); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CGlobalCountPage, CVerifierPropertyPage) //{{AFX_MSG_MAP(CGlobalCountPage) ON_WM_TIMER() ON_NOTIFY(LVN_COLUMNCLICK, IDC_GLOBC_LIST, OnColumnclickGlobcList) ON_WM_CONTEXTMENU() ON_MESSAGE( WM_HELP, OnHelp ) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////// VOID CGlobalCountPage::SetupListHeader() { LVCOLUMN lvColumn; CRect rectWnd; CString strCounter, strValue; VERIFY( strCounter.LoadString( IDS_COUNTER ) ); VERIFY( strValue.LoadString( IDS_VALUE ) ); // // List's regtangle // m_CountersList.GetClientRect( &rectWnd ); // // Column 0 - counter // ZeroMemory( &lvColumn, sizeof( lvColumn ) ); lvColumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; lvColumn.fmt = LVCFMT_LEFT; lvColumn.iSubItem = 0; lvColumn.cx = (int)( rectWnd.Width() * 0.50 ); lvColumn.pszText = strCounter.GetBuffer( strCounter.GetLength() + 1 ); if (NULL != lvColumn.pszText) { VERIFY( m_CountersList.InsertColumn( 0, &lvColumn ) != -1 ); strCounter.ReleaseBuffer(); } else { lvColumn.pszText = g_szVoidText; VERIFY( m_CountersList.InsertColumn( 0, &lvColumn ) != -1 ); } // // Column 1 // lvColumn.iSubItem = 1; lvColumn.cx = (int)( rectWnd.Width() * 0.47 ); lvColumn.pszText = strValue.GetBuffer( strValue.GetLength() + 1 ); if (NULL != lvColumn.pszText) { VERIFY( m_CountersList.InsertColumn( 1, &lvColumn ) != -1 ); strValue.ReleaseBuffer(); } else { lvColumn.pszText = g_szVoidText; VERIFY( m_CountersList.InsertColumn( 1, &lvColumn ) != -1 ); } } ///////////////////////////////////////////////////////////// VOID CGlobalCountPage::FillTheList() { // // N.B. // // If you change the first parameter (index - stored in the item's data) // you need to change the switch statement in GetCounterValue as well // AddCounterInList( 0, IDS_ALLOCATIONSATTEMPTED_LIST, m_RuntimeVerifierData.AllocationsAttempted ); AddCounterInList( 1, IDS_ALLOCATIONSSUCCEEDED_LIST, m_RuntimeVerifierData.AllocationsSucceeded ); AddCounterInList( 2, IDS_ALLOCATIONSSUCCEEDEDSPECIALPOOL_LIST, m_RuntimeVerifierData.AllocationsSucceededSpecialPool ); AddCounterInList( 3, IDS_ALLOCATIONSWITHNOTAG_LIST, m_RuntimeVerifierData.AllocationsWithNoTag ); AddCounterInList( 4, IDS_UNTRACKEDPOOL_LIST, m_RuntimeVerifierData.UnTrackedPool ); AddCounterInList( 5, IDS_ALLOCATIONSFAILED_LIST, m_RuntimeVerifierData.AllocationsFailed ); AddCounterInList( 6, IDS_ALLOCATIONSFAILEDDELIBERATELY_LIST, m_RuntimeVerifierData.AllocationsFailedDeliberately ); AddCounterInList( 7, IDS_RAISEIRQLS_LIST, m_RuntimeVerifierData.RaiseIrqls ); AddCounterInList( 8, IDS_ACQUIRESPINLOCKS_LIST, m_RuntimeVerifierData.AcquireSpinLocks ); AddCounterInList( 9, IDS_SYNCHRONIZEEXECUTIONS_LIST, m_RuntimeVerifierData.SynchronizeExecutions ); AddCounterInList( 10, IDS_TRIMS_LIST, m_RuntimeVerifierData.Trims ); } ///////////////////////////////////////////////////////////// VOID CGlobalCountPage::RefreshTheList() { INT nListItems; INT nCrtListItem; INT_PTR nCrtCounterIndex; SIZE_T sizeValue; nListItems = m_CountersList.GetItemCount(); for( nCrtListItem = 0; nCrtListItem < nListItems; nCrtListItem += 1 ) { nCrtCounterIndex = m_CountersList.GetItemData( nCrtListItem ); sizeValue = GetCounterValue( nCrtCounterIndex ); UpdateCounterValueInList( nCrtListItem, sizeValue ); } } ///////////////////////////////////////////////////////////// VOID CGlobalCountPage::SortTheList() { if( 0 != m_nSortColumnIndex ) { // // Sort by counter value - this is probably not very useful // but we are providing it to be consistent with all // the lists being sortable by any column // m_CountersList.SortItems( CounterValueCmpFunc, (LPARAM)this ); } else { // // Sort by driver name // m_CountersList.SortItems( CounterNameCmpFunc, (LPARAM)this ); } } ///////////////////////////////////////////////////////////// SIZE_T CGlobalCountPage::GetCounterValue( INT_PTR nCounterIndex ) { SIZE_T sizeValue; // // N.B. // // If you change this switch statement you need to change FillTheList as well // switch( nCounterIndex ) { case 0: sizeValue = m_RuntimeVerifierData.AllocationsAttempted; break; case 1: sizeValue = m_RuntimeVerifierData.AllocationsSucceeded; break; case 2: sizeValue = m_RuntimeVerifierData.AllocationsSucceededSpecialPool; break; case 3: sizeValue = m_RuntimeVerifierData.AllocationsWithNoTag; break; case 4: sizeValue = m_RuntimeVerifierData.UnTrackedPool; break; case 5: sizeValue = m_RuntimeVerifierData.AllocationsFailed; break; case 6: sizeValue = m_RuntimeVerifierData.AllocationsFailedDeliberately; break; case 7: sizeValue = m_RuntimeVerifierData.RaiseIrqls; break; case 8: sizeValue = m_RuntimeVerifierData.AcquireSpinLocks; break; case 9: sizeValue = m_RuntimeVerifierData.SynchronizeExecutions; break; case 10: sizeValue = m_RuntimeVerifierData.Trims; break; default: // // Oops, how did we get here ?!? // ASSERT( FALSE ); sizeValue = 0; break; } return sizeValue; } ///////////////////////////////////////////////////////////// BOOL CGlobalCountPage::GetCounterName( LPARAM lItemData, TCHAR *szCounterName, ULONG uCounterNameBufferLen ) { INT nItemIndex; BOOL bResult; LVFINDINFO FindInfo; LVITEM lvItem; bResult = FALSE; ZeroMemory( &FindInfo, sizeof( FindInfo ) ); FindInfo.flags = LVFI_PARAM; FindInfo.lParam = lItemData; nItemIndex = m_CountersList.FindItem( &FindInfo ); if( nItemIndex < 0 || nItemIndex > 10 ) { ASSERT( FALSE ); } else { // // Found our item - get the name // ZeroMemory( &lvItem, sizeof( lvItem ) ); lvItem.mask = LVIF_TEXT; lvItem.iItem = nItemIndex; lvItem.iSubItem = 0; lvItem.pszText = szCounterName; lvItem.cchTextMax = uCounterNameBufferLen; bResult = m_CountersList.GetItem( &lvItem ); if( bResult == FALSE ) { // // Could not get the current item's attributes?!? // ASSERT( FALSE ); } } return bResult; } ///////////////////////////////////////////////////////////// VOID CGlobalCountPage::AddCounterInList( INT nItemData, ULONG uIdResourceString, SIZE_T sizeValue ) { INT nActualIndex; LVITEM lvItem; CString strName; VERIFY( strName.LoadString( uIdResourceString ) ); ZeroMemory( &lvItem, sizeof( lvItem ) ); // // LVITEM's member pszText is not a const pointer // so we need to GetBuffer here :-( // // // Sub-item 0 - counter's name // lvItem.pszText = strName.GetBuffer( strName.GetLength() + 1 ); if( NULL == lvItem.pszText ) { goto Done; } lvItem.mask = LVIF_TEXT | LVIF_PARAM; lvItem.lParam = nItemData; lvItem.iItem = m_CountersList.GetItemCount(); nActualIndex = m_CountersList.InsertItem( &lvItem ); if( nActualIndex < 0 ) { // // Could not add an item in the list - give up // goto Done; } // // Sub-item 1 - counter's value // UpdateCounterValueInList( nActualIndex, sizeValue ); Done: // // All done // NOTHING; } ///////////////////////////////////////////////////////////// VOID CGlobalCountPage::RefreshInfo() { if( UpdateData( FALSE ) ) { // // Refresh the settings bits list // RefreshTheList(); } } ///////////////////////////////////////////////////////////// VOID CGlobalCountPage::UpdateCounterValueInList( INT nItemIndex, SIZE_T sizeValue ) { TCHAR szValue[ 32 ]; LVITEM lvItem; #ifndef _WIN64 // // 32 bit SIZE_T // _sntprintf( szValue, ARRAY_LENGTH( szValue ), _T( "%u" ), sizeValue ); #else // // 64 bit SIZE_T // _sntprintf( szValue, ARRAY_LENGTH( szValue ), _T( "%I64u" ), sizeValue ); #endif szValue[ ARRAY_LENGTH( szValue ) - 1 ] = 0; // // Update the list item // ZeroMemory( &lvItem, sizeof( lvItem ) ); lvItem.mask = LVIF_TEXT; lvItem.iItem = nItemIndex; lvItem.iSubItem = 1; lvItem.pszText = szValue; VERIFY( m_CountersList.SetItem( &lvItem ) ); } ///////////////////////////////////////////////////////////// // // Other methods // ///////////////////////////////////////////////////////////// #define MIN_MEM_SIZE_TO_DISABLE_WARNING 0x80000000 // 2 Gb #define MIN_ALLOCATIONS_SIGNIFICANT 100 #define MIN_PERCENTAGE_AVOID_WARNING 95 BOOL CGlobalCountPage::CheckAndShowPoolCoverageWarning() { BOOL bWarningDisplayed; ULONGLONG ullPercentageCoverage; TCHAR *szMessage; CString strMsgFormat; CString strWarnMsg; bWarningDisplayed = FALSE; if( m_RuntimeVerifierData.m_bSpecialPool && m_RuntimeVerifierData.AllocationsSucceeded >= MIN_ALLOCATIONS_SIGNIFICANT ) { // // Special pool verification is enabled && // There is a significant number of allocations // ASSERT( m_RuntimeVerifierData.AllocationsSucceeded >= m_RuntimeVerifierData.AllocationsSucceededSpecialPool ); // // The coverage percentage // ullPercentageCoverage = ( (ULONGLONG)m_RuntimeVerifierData.AllocationsSucceededSpecialPool * (ULONGLONG) 100 ) / (ULONGLONG)m_RuntimeVerifierData.AllocationsSucceeded; ASSERT( ullPercentageCoverage <= 100 ); if( ullPercentageCoverage < MIN_PERCENTAGE_AVOID_WARNING ) { // // Warn the user // if( strMsgFormat.LoadString( IDS_COVERAGE_WARNING_FORMAT ) ) { szMessage = strWarnMsg.GetBuffer( strMsgFormat.GetLength() + 32 ); if( szMessage != NULL ) { _stprintf( szMessage, (LPCTSTR)strMsgFormat, ullPercentageCoverage ); strWarnMsg.ReleaseBuffer(); AfxMessageBox( strWarnMsg, MB_OK | MB_ICONINFORMATION ); } } else { ASSERT( FALSE ); } bWarningDisplayed = TRUE; } } return bWarningDisplayed; } ///////////////////////////////////////////////////////////// int CALLBACK CGlobalCountPage::CounterValueCmpFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { SIZE_T size1; SIZE_T size2; int nCmpRez = 0; CGlobalCountPage *pThis = (CGlobalCountPage *)lParamSort; ASSERT_VALID( pThis ); size1 = pThis->GetCounterValue( (INT) lParam1 ); size2 = pThis->GetCounterValue( (INT) lParam2 ); if( size1 > size2 ) { nCmpRez = 1; } else { if( size1 < size2 ) { nCmpRez = -1; } } if( FALSE != pThis->m_bAscendSortValue ) { nCmpRez *= -1; } return nCmpRez; } ///////////////////////////////////////////////////////////// int CALLBACK CGlobalCountPage::CounterNameCmpFunc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { int nCmpRez = 0; BOOL bSuccess; TCHAR szCounterName1[ _MAX_PATH ]; TCHAR szCounterName2[ _MAX_PATH ]; CGlobalCountPage *pThis = (CGlobalCountPage *)lParamSort; ASSERT_VALID( pThis ); // // Get the first counter name // bSuccess = pThis->GetCounterName( lParam1, szCounterName1, ARRAY_LENGTH( szCounterName1 ) ); if( FALSE == bSuccess ) { goto Done; } // // Get the second counter name // bSuccess = pThis->GetCounterName( lParam2, szCounterName2, ARRAY_LENGTH( szCounterName2 ) ); if( FALSE == bSuccess ) { goto Done; } // // Compare the names // nCmpRez = _tcsicmp( szCounterName1, szCounterName2 ); if( FALSE != pThis->m_bAscendSortName ) { nCmpRez *= -1; } Done: return nCmpRez; } ///////////////////////////////////////////////////////////// // CGlobalCountPage message handlers BOOL CGlobalCountPage::OnInitDialog() { CPropertyPage::OnInitDialog(); // // Setup the settings bits list // m_CountersList.SetExtendedStyle( LVS_EX_FULLROWSELECT | m_CountersList.GetExtendedStyle() ); m_CountersList.SetBkColor( ::GetSysColor( COLOR_3DFACE ) ); m_CountersList.SetTextBkColor( ::GetSysColor( COLOR_3DFACE ) ); SetupListHeader(); FillTheList(); SortTheList(); VrfSetWindowText( m_NextDescription, IDS_GCNT_PAGE_NEXT_DESCR ); VERIFY( m_uTimerHandler = SetTimer( REFRESH_TIMER_ID, 5000, NULL ) ); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } ///////////////////////////////////////////////////////////// VOID CGlobalCountPage::OnTimer(UINT nIDEvent) { if( nIDEvent == REFRESH_TIMER_ID ) { ASSERT_VALID( m_pParentSheet ); if( m_pParentSheet->GetActivePage() == this ) { // // Refresh the displayed data // RefreshInfo(); } } CPropertyPage::OnTimer(nIDEvent); } ///////////////////////////////////////////////////////////////////////////// BOOL CGlobalCountPage::OnSetActive() { ASSERT_VALID( m_pParentSheet ); m_pParentSheet->SetWizardButtons( PSWIZB_BACK | PSWIZB_NEXT ); return CVerifierPropertyPage::OnSetActive(); } ///////////////////////////////////////////////////////////////////////////// LRESULT CGlobalCountPage::OnWizardNext() { GoingToNextPageNotify( IDD_PERDRIVER_COUNTERS_PAGE ); return IDD_PERDRIVER_COUNTERS_PAGE; } ///////////////////////////////////////////////////////////////////////////// void CGlobalCountPage::OnColumnclickGlobcList(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if( 0 != pNMListView->iSubItem ) { // // Clicked on the counter value column // if( m_nSortColumnIndex == pNMListView->iSubItem ) { // // Change the current ascend/descend order for this column // m_bAscendSortValue = !m_bAscendSortValue; } } else { // // Clicked on the counter name column // if( m_nSortColumnIndex == pNMListView->iSubItem ) { // // Change the current ascend/descend order for this column // m_bAscendSortName = !m_bAscendSortName; } } m_nSortColumnIndex = pNMListView->iSubItem; SortTheList(); *pResult = 0; } ///////////////////////////////////////////////////////////// LONG CGlobalCountPage::OnHelp( WPARAM wParam, LPARAM lParam ) { LONG lResult = 0; LPHELPINFO lpHelpInfo = (LPHELPINFO)lParam; ::WinHelp( (HWND) lpHelpInfo->hItemHandle, g_szVerifierHelpFile, HELP_WM_HELP, (DWORD_PTR) MyHelpIds ); return lResult; } ///////////////////////////////////////////////////////////////////////////// void CGlobalCountPage::OnContextMenu(CWnd* pWnd, CPoint point) { ::WinHelp( pWnd->m_hWnd, g_szVerifierHelpFile, HELP_CONTEXTMENU, (DWORD_PTR) MyHelpIds ); }