Что я хотел бы сделать, так это написать небольшую программу, которая постоянно работает, подсчитывает количество переключений контекста, которое происходит в конкретном процессе за достаточно малую единицу времени. Я наблюдал эту функциональность в программном обеспечении «Process Explorer», поэтому я знаю, что это определенно возможно.
К сожалению, я очень мало представляю, как начать это кодировать, и до сих пор не смог найти в Интернете никаких полезных фрагментов кода. Таким образом, небольшой рабочий пример, реализующий подсчет переключений контекста в реальном времени и за единицу времени, был бы для меня чрезвычайно полезным.
Вот один из способов сделать это — это будет печатать количество переключений контекста, используемых потоком 0 блокнота (вы можете заменить любой процесс и номер потока, который вы хотите при инициализации CounterPathBuffer) каждую секунду:
#include "stdafx.h"#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <pdh.h>
#include <pdhmsg.h>
#pragma comment(lib, "pdh.lib")
using namespace std;
CONST ULONG SAMPLE_INTERVAL_MS = 1000;
CONST PWSTR BROWSE_DIALOG_CAPTION = L"Select a counter to monitor.";
void wmain(void)
{
PDH_STATUS Status;
HQUERY Query = NULL;
HCOUNTER Counter;
PDH_FMT_COUNTERVALUE DisplayValue;
DWORD CounterType;
SYSTEMTIME SampleTime;
PDH_BROWSE_DLG_CONFIG BrowseDlgData;
WCHAR CounterPathBuffer[PDH_MAX_COUNTER_PATH] = L"\\\\ComputerNameGoesHere\\Thread(notepad/0)\\Context Switches/sec";//
// Create a query.
//
Status = PdhOpenQuery(NULL, NULL, &Query);
if (Status != ERROR_SUCCESS)
{
wprintf(L"\nPdhOpenQuery failed with status 0x%x.", Status);
goto Cleanup;
}
//
// Initialize the browser dialog window settings.
//ZeroMemory(&BrowseDlgData, sizeof(PDH_BROWSE_DLG_CONFIG));
BrowseDlgData.bIncludeInstanceIndex = FALSE;
BrowseDlgData.bSingleCounterPerAdd = TRUE;
BrowseDlgData.bSingleCounterPerDialog = TRUE;
BrowseDlgData.bLocalCountersOnly = FALSE;
BrowseDlgData.bWildCardInstances = TRUE;
BrowseDlgData.bHideDetailBox = TRUE;
BrowseDlgData.bInitializePath = FALSE;
BrowseDlgData.bDisableMachineSelection = FALSE;
BrowseDlgData.bIncludeCostlyObjects = FALSE;
BrowseDlgData.bShowObjectBrowser = FALSE;
BrowseDlgData.hWndOwner = NULL;
BrowseDlgData.szReturnPathBuffer = CounterPathBuffer;
BrowseDlgData.cchReturnPathLength = PDH_MAX_COUNTER_PATH;
BrowseDlgData.pCallBack = NULL;
BrowseDlgData.dwCallBackArg = 0;
BrowseDlgData.CallBackStatus = ERROR_SUCCESS;
BrowseDlgData.dwDefaultDetailLevel = PERF_DETAIL_WIZARD;
BrowseDlgData.szDialogBoxCaption = BROWSE_DIALOG_CAPTION;
//
// Add the selected counter to the query.
//Status = PdhAddCounter(Query, CounterPathBuffer, 0, &Counter);
if (Status != ERROR_SUCCESS)
{
wprintf(L"\nPdhAddCounter failed with status 0x%x.", Status);
goto Cleanup;
}
//
// Most counters require two sample values to display a formatted value.
// PDH stores the current sample value and the previously collected
// sample value. This call retrieves the first value that will be used
// by PdhGetFormattedCounterValue in the first iteration of the loop
// Note that this value is lost if the counter does not require two
// values to compute a displayable value.
//
Status = PdhCollectQueryData(Query);
if (Status != ERROR_SUCCESS)
{
wprintf(L"\nPdhCollectQueryData failed with 0x%x.\n", Status);
goto Cleanup;
}
//
// Print counter values until a key is pressed.
//
while (!_kbhit())
{
Sleep(SAMPLE_INTERVAL_MS);
GetLocalTime(&SampleTime);
Status = PdhCollectQueryData(Query);
if (Status != ERROR_SUCCESS)
{
wprintf(L"\nPdhCollectQueryData failed with status 0x%x.", Status);
}
wprintf(L"\n\"%2.2d/%2.2d/%4.4d %2.2d:%2.2d:%2.2d.%3.3d\"",
SampleTime.wMonth,
SampleTime.wDay,
SampleTime.wYear,
SampleTime.wHour,
SampleTime.wMinute,
SampleTime.wSecond,
SampleTime.wMilliseconds);
//
// Compute a displayable value for the counter.
//
Status = PdhGetFormattedCounterValue(Counter,
PDH_FMT_DOUBLE,
&CounterType,
&DisplayValue);
if (Status != ERROR_SUCCESS)
{
wprintf(L"\nPdhGetFormattedCounterValue failed with status 0x%x.", Status);
goto Cleanup;
}wprintf(L",\"%.20g\"", DisplayValue.doubleValue);
}
Cleanup:
//
// Close the query.
//
if (Query)
{
PdhCloseQuery(Query);
}
int x;
cin >>x;
}
Большая часть кода из этого источника: msdn.microsoft.com/en-us/library/aa371886%28v=vs.85%29.aspx. Я хотел бы сократить количество времени между последовательными проверками переключений контекста (сделать его менее секунды). Если у кого-то есть идеи, как это сделать, это было бы здорово.
Немного поиска в интернете и я нашел эту вещь под названием «Счетчики производительности«, вы можете либо предоставить данные счетчика, либо использовать данные счетчика вместе с ним. В вашем случае, я полагаю, вы хотите прочитать данные из счетчиков производительности.
Вы можете использовать данные о производительности, используя интерфейс реестра или интерфейс PDH. Интерфейс PDH проще в использовании, чем интерфейс реестра, и рекомендуется для большинства задач сбора данных о производительности. Интерфейс PDH — это абстракция более высокого уровня функциональности, которую обеспечивает интерфейс реестра.
Вот еще одна статья от Microsoft на Мониторинг переключений контекста.
ETW (Event Tracing for Windows) даст вам гораздо более глубокую информацию о переключениях контекста, если хотите. Код, вероятно, будет значительно сложнее, чем доступ к счетчикам производительности.
Начальные ссылки: Основные события ОС в Windows 7 а также Технический справочник по Windows Performance Toolkit
Поисковые термины: «переключатели контекста ETW», «xperf»