Подсчет переключений контекста для определенного процесса в Windows

Что я хотел бы сделать, так это написать небольшую программу, которая постоянно подсчитывает количество переключений контекста, которые испытывает конкретный процесс за достаточно небольшую единицу времени. Я наблюдал эту функциональность в программном обеспечении «Process Explorer», поэтому я знаю, что это определенно возможно.

К сожалению, я очень плохо представляю, как начать кодировать это, и до сих пор не смог найти какие-либо полезные фрагменты кода в Интернете. Таким образом, небольшой рабочий пример, реализующий подсчет переключений живого контекста для каждого процесса и в единицу времени, был бы для меня чрезвычайно полезен.


person John Roberts    schedule 26.09.2012    source источник


Ответы (3)


Вот один из способов сделать это. Это будет печатать количество переключений контекста, используемых потоком 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. Я хотел бы сократить время между последовательными проверками переключения контекста (сделать его менее секунды). Если у кого-то есть идеи, как это сделать, было бы здорово.

person John Roberts    schedule 29.09.2012
comment
Вы должны указывать, где вы получаете вещи, если вы просто копируете / вставляете. Например, вы получили свой от: msdn. microsoft.com/en-us/library/aa371886%28v=vs.85%29.aspx - person CrazyCasta; 29.09.2012
comment
Не совсем сырая копия/вставка, но вы правы. Теперь я добавил источник. - person John Roberts; 29.09.2012
comment
Что произойдет, если вы установите SAMPLE_INTERVAL_MS на меньшее число, скажем, 100? Разве вы не получаете десять результатов в секунду? - person Harry Johnston; 01.10.2012
comment
Молодец, спасибо, что указал на очевидное. Если вы предоставите это в качестве ответа, я буду рад дать вам награду. - person John Roberts; 04.10.2012

Немного поискав в Интернете, я нашел эту штуку под названием "Счетчики производительности", вы можете либо предоставить данные счетчика, либо использовать данные счетчика вместе с ними. В вашем случае, я полагаю, вы хотите прочитать данные из счетчиков производительности.

Вы можете получать данные о производительности, используя либо интерфейс реестра, либо интерфейс PDH. Интерфейс PDH проще в использовании, чем интерфейс реестра, и рекомендуется для большинства задач сбора данных о производительности. Интерфейс PDH, по сути, представляет собой абстракцию более высокого уровня функций, предоставляемых интерфейсом реестра.

Вот еще одна статья Microsoft об отслеживании переключений контекста.

person user1032613    schedule 29.09.2012
comment
Я прочитал оба источника, которые вы уже цитировали. Ни один из них не предоставляет рабочий пример, который я запросил. - person John Roberts; 29.09.2012

ETW (отслеживание событий для Windows) даст вам гораздо более подробную информацию о переключениях контекста, если вы хотите. Код, вероятно, будет значительно сложнее, чем доступ к счетчикам производительности.

Начальные ссылки: События базовой ОС в Windows 7 и Технический справочник по Windows Performance Toolkit

Условия поиска: «переключатели контекста ETW», «xperf».

person Alexei Levenkov    schedule 04.10.2012
comment
Если вы можете предоставить мне простой пример использования ETW для достижения моей цели, я буду рад дать вам награду. - person John Roberts; 05.10.2012
comment
@ДжонРобертс, извини. Мне никогда не приходилось читать ETW самому — в моем случае для офлайн-расследований было достаточно существующих инструментов. - person Alexei Levenkov; 05.10.2012