Преброяване на контекстни превключватели за конкретен процес в 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) ще ви даде много по-задълбочена информация за контекстните превключватели, ако искате. Кодът вероятно е значително по-сложен от достъпа до броячи на производителност.

Първоначални връзки: Core OS Събития в Windows 7 и Техническа справка за Windows Performance Toolkit

Термини за търсене: „ETW контекстни превключватели“, „xperf“

person Alexei Levenkov    schedule 04.10.2012
comment
Ако можете да ми предоставите прост пример за използване на ETW за постигане на моята цел, ще се радвам да ви дам наградата. - person John Roberts; 05.10.2012
comment
@JohnRoberts, съжалявам. Никога не ми се налага да чета ETW - в моя случай съществуващите инструменти бяха достатъчни за офлайн разследвания. - person Alexei Levenkov; 05.10.2012