Як визначити споживання процесора та пам'яті всередині процесу?


593

Колись у мене було завдання визначити наступні параметри продуктивності з всередині запущеної програми:

  • Загальна віртуальна пам'ять
  • В даний час використовується віртуальна пам'ять
  • Віртуальна пам'ять, яку зараз використовує мій процес
  • Загальна доступна оперативна пам’ять
  • В даний час використовується оперативна пам’ять
  • На даний момент оперативна пам’ять використовується моїм процесом
  • Зараз використовується% CPU
  • % CPU, який зараз використовується у моєму процесі

Код повинен був працювати в Windows та Linux. Незважаючи на те, що це здається стандартним завданням, пошук потрібної інформації в посібниках (API WIN32, документах GNU), а також в Інтернеті зайняв у мене кілька днів, тому що на цю тему є стільки неповної / некоректної / застарілої інформації. знайшли там.

Для того, щоб врятувати інших людей від тих самих неприємностей, я подумав, що було б гарною ідеєю зібрати всю розкидану інформацію плюс те, що я знайшов тут шляхом спроб та помилок в одному місці.


13
"Загальна доступна віртуальна пам'ять" безглузда в сучасних операційних системах.
Девід Шварц

29
Чому це безглуздо? Чи не відповідає це відповідь тут? stackoverflow.com/questions/3296211/… ... Будь ласка, не залишайте скелястих, коли коментуєте, це не телешоу.
Міндоўг Бернатавічус

3
@ MindaugasBernatavičius: Пов’язане питання стосується "загальної фізичної пам'яті", що є апаратним фактом, відомим ОС. Ви отримуєте загальну суму, додаючи розміри всіх модулів пам'яті. "Загальна доступна віртуальна пам'ять", з іншого боку, що це навіть означає? Це поєднаний віртуальний адресний простір усіх процесів, які теоретично можна було б створити? Це число було б близько 2 ^ 80 байт, так що, безумовно, безглуздо.
MSalters

2
@MSalters - дякую за залучення. Я вважаю, що запитувати те, про що мав на увазі, це набагато добріше і здоровіше, ніж заявляти, що щось є безглуздим (без пояснень). Якщо ви зауважуєте, відповіді також займають певну позицію щодо цього: Віртуальна пам'ять = RAM + SWAP (або PAGEFILE) - що є розумним припущенням. З цього ми знаємо, що це не має сенсу, оскільки існує певне тлумачення цього терміна (який, можливо, не є найбільш технічно правильним, колоквілізм), який має значення.
Міндовг Бернатавічус

2
@ MindaugasBernatavičius: Це ігнорує файли та код, відображений у пам'яті, які не завантажуються в стадію. Linux має нерозподілений розподіл пам’яті (не підтримується оперативною пам’яттю або свопом), а Windows має стеки, що не виконуються.
MSalters

Відповіді:


644

Windows

Деякі з перерахованих вище значень легко доступні у відповідному API WIN32, я лише перелічу їх тут для повноти. Інші, однак, потрібно отримати у бібліотеці продуктивних помічників продуктивності (PDH), яка є дещо "неінтуїтивною" та потребує багато болісних спроб та помилок, щоб приступити до роботи. (Принаймні, це зайняло у мене досить багато часу, можливо, я була лише трохи дурною ...)

Примітка: для наочності всі перевірки помилок були виключені з наступного коду. Перевірте коди повернення ...!


  • Загальна віртуальна пам'ять:

    #include "windows.h"
    
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&memInfo);
    DWORDLONG totalVirtualMem = memInfo.ullTotalPageFile;

    Примітка. Назва "TotalPageFile" тут трохи вводить в оману. Насправді цей параметр дає "Розмір віртуальної пам'яті", який є розміром файла swap плюс встановленої оперативної пам'яті.

  • В даний час використовується віртуальна пам'ять:

    Той самий код, що і в "Загальна віртуальна пам'ять", а потім

    DWORDLONG virtualMemUsed = memInfo.ullTotalPageFile - memInfo.ullAvailPageFile;
  • Віртуальна пам'ять, що використовується в поточному процесі:

    #include "windows.h"
    #include "psapi.h"
    
    PROCESS_MEMORY_COUNTERS_EX pmc;
    GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
    SIZE_T virtualMemUsedByMe = pmc.PrivateUsage;



  • Загальна фізична пам'ять (ОЗП):

    Той самий код, що і в "Загальна віртуальна пам'ять", а потім

    DWORDLONG totalPhysMem = memInfo.ullTotalPhys;
  • В даний час використовується фізична пам'ять:

    Same code as in "Total Virtual Memory" and then
    
    DWORDLONG physMemUsed = memInfo.ullTotalPhys - memInfo.ullAvailPhys;
  • Фізична пам'ять, що використовується в поточному процесі:

    Той самий код, що і у "Віртуальній пам'яті, що використовується в поточному процесі", а потім

    SIZE_T physMemUsedByMe = pmc.WorkingSetSize;



  • В даний час використовується процесор:

    #include "TCHAR.h"
    #include "pdh.h"
    
    static PDH_HQUERY cpuQuery;
    static PDH_HCOUNTER cpuTotal;
    
    void init(){
        PdhOpenQuery(NULL, NULL, &cpuQuery);
        // You can also use L"\\Processor(*)\\% Processor Time" and get individual CPU values with PdhGetFormattedCounterArray()
        PdhAddEnglishCounter(cpuQuery, L"\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal);
        PdhCollectQueryData(cpuQuery);
    }
    
    double getCurrentValue(){
        PDH_FMT_COUNTERVALUE counterVal;
    
        PdhCollectQueryData(cpuQuery);
        PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
        return counterVal.doubleValue;
    }
  • Процесор, який зараз використовується в поточному процесі:

    #include "windows.h"
    
    static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;
    static int numProcessors;
    static HANDLE self;
    
    void init(){
        SYSTEM_INFO sysInfo;
        FILETIME ftime, fsys, fuser;
    
        GetSystemInfo(&sysInfo);
        numProcessors = sysInfo.dwNumberOfProcessors;
    
        GetSystemTimeAsFileTime(&ftime);
        memcpy(&lastCPU, &ftime, sizeof(FILETIME));
    
        self = GetCurrentProcess();
        GetProcessTimes(self, &ftime, &ftime, &fsys, &fuser);
        memcpy(&lastSysCPU, &fsys, sizeof(FILETIME));
        memcpy(&lastUserCPU, &fuser, sizeof(FILETIME));
    }
    
    double getCurrentValue(){
        FILETIME ftime, fsys, fuser;
        ULARGE_INTEGER now, sys, user;
        double percent;
    
        GetSystemTimeAsFileTime(&ftime);
        memcpy(&now, &ftime, sizeof(FILETIME));
    
        GetProcessTimes(self, &ftime, &ftime, &fsys, &fuser);
        memcpy(&sys, &fsys, sizeof(FILETIME));
        memcpy(&user, &fuser, sizeof(FILETIME));
        percent = (sys.QuadPart - lastSysCPU.QuadPart) +
            (user.QuadPart - lastUserCPU.QuadPart);
        percent /= (now.QuadPart - lastCPU.QuadPart);
        percent /= numProcessors;
        lastCPU = now;
        lastUserCPU = user;
        lastSysCPU = sys;
    
        return percent * 100;
    }

Linux

У Linux вибір, який спочатку здавався очевидним, - це використовувати такі POSIX API, як getrusage()і т.д. Коли я нарешті перевірив самі джерела ядра, я виявив, що, очевидно, ці API ще не повністю реалізовані як Linux Linux kernel 2.6!?

Зрештою, я отримав усі значення за допомогою комбінації зчитування псевдофайлової системи /procта викликів ядра.

  • Загальна віртуальна пам'ять:

    #include "sys/types.h"
    #include "sys/sysinfo.h"
    
    struct sysinfo memInfo;
    
    sysinfo (&memInfo);
    long long totalVirtualMem = memInfo.totalram;
    //Add other values in next statement to avoid int overflow on right hand side...
    totalVirtualMem += memInfo.totalswap;
    totalVirtualMem *= memInfo.mem_unit;
  • В даний час використовується віртуальна пам'ять:

    Той самий код, що і в "Загальна віртуальна пам'ять", а потім

    long long virtualMemUsed = memInfo.totalram - memInfo.freeram;
    //Add other values in next statement to avoid int overflow on right hand side...
    virtualMemUsed += memInfo.totalswap - memInfo.freeswap;
    virtualMemUsed *= memInfo.mem_unit;
  • Віртуальна пам'ять, що використовується в поточному процесі:

    #include "stdlib.h"
    #include "stdio.h"
    #include "string.h"
    
    int parseLine(char* line){
        // This assumes that a digit will be found and the line ends in " Kb".
        int i = strlen(line);
        const char* p = line;
        while (*p <'0' || *p > '9') p++;
        line[i-3] = '\0';
        i = atoi(p);
        return i;
    }
    
    int getValue(){ //Note: this value is in KB!
        FILE* file = fopen("/proc/self/status", "r");
        int result = -1;
        char line[128];
    
        while (fgets(line, 128, file) != NULL){
            if (strncmp(line, "VmSize:", 7) == 0){
                result = parseLine(line);
                break;
            }
        }
        fclose(file);
        return result;
    }



  • Загальна фізична пам'ять (ОЗП):

    Той самий код, що і в "Загальна віртуальна пам'ять", а потім

    long long totalPhysMem = memInfo.totalram;
    //Multiply in next statement to avoid int overflow on right hand side...
    totalPhysMem *= memInfo.mem_unit;
  • В даний час використовується фізична пам'ять:

    Той самий код, що і в "Загальна віртуальна пам'ять", а потім

    long long physMemUsed = memInfo.totalram - memInfo.freeram;
    //Multiply in next statement to avoid int overflow on right hand side...
    physMemUsed *= memInfo.mem_unit;
  • Фізична пам'ять, що використовується в поточному процесі:

    Змініть getValue () у "Віртуальна пам'ять, яку зараз використовує поточний процес" таким чином:

    int getValue(){ //Note: this value is in KB!
        FILE* file = fopen("/proc/self/status", "r");
        int result = -1;
        char line[128];
    
        while (fgets(line, 128, file) != NULL){
            if (strncmp(line, "VmRSS:", 6) == 0){
                result = parseLine(line);
                break;
            }
        }
        fclose(file);
        return result;
    }



  • В даний час використовується процесор:

    #include "stdlib.h"
    #include "stdio.h"
    #include "string.h"
    
    static unsigned long long lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle;
    
    void init(){
        FILE* file = fopen("/proc/stat", "r");
        fscanf(file, "cpu %llu %llu %llu %llu", &lastTotalUser, &lastTotalUserLow,
            &lastTotalSys, &lastTotalIdle);
        fclose(file);
    }
    
    double getCurrentValue(){
        double percent;
        FILE* file;
        unsigned long long totalUser, totalUserLow, totalSys, totalIdle, total;
    
        file = fopen("/proc/stat", "r");
        fscanf(file, "cpu %llu %llu %llu %llu", &totalUser, &totalUserLow,
            &totalSys, &totalIdle);
        fclose(file);
    
        if (totalUser < lastTotalUser || totalUserLow < lastTotalUserLow ||
            totalSys < lastTotalSys || totalIdle < lastTotalIdle){
            //Overflow detection. Just skip this value.
            percent = -1.0;
        }
        else{
            total = (totalUser - lastTotalUser) + (totalUserLow - lastTotalUserLow) +
                (totalSys - lastTotalSys);
            percent = total;
            total += (totalIdle - lastTotalIdle);
            percent /= total;
            percent *= 100;
        }
    
        lastTotalUser = totalUser;
        lastTotalUserLow = totalUserLow;
        lastTotalSys = totalSys;
        lastTotalIdle = totalIdle;
    
        return percent;
    }
  • Процесор, який зараз використовується в поточному процесі:

    #include "stdlib.h"
    #include "stdio.h"
    #include "string.h"
    #include "sys/times.h"
    #include "sys/vtimes.h"
    
    static clock_t lastCPU, lastSysCPU, lastUserCPU;
    static int numProcessors;
    
    void init(){
        FILE* file;
        struct tms timeSample;
        char line[128];
    
        lastCPU = times(&timeSample);
        lastSysCPU = timeSample.tms_stime;
        lastUserCPU = timeSample.tms_utime;
    
        file = fopen("/proc/cpuinfo", "r");
        numProcessors = 0;
        while(fgets(line, 128, file) != NULL){
            if (strncmp(line, "processor", 9) == 0) numProcessors++;
        }
        fclose(file);
    }
    
    double getCurrentValue(){
        struct tms timeSample;
        clock_t now;
        double percent;
    
        now = times(&timeSample);
        if (now <= lastCPU || timeSample.tms_stime < lastSysCPU ||
            timeSample.tms_utime < lastUserCPU){
            //Overflow detection. Just skip this value.
            percent = -1.0;
        }
        else{
            percent = (timeSample.tms_stime - lastSysCPU) +
                (timeSample.tms_utime - lastUserCPU);
            percent /= (now - lastCPU);
            percent /= numProcessors;
            percent *= 100;
        }
        lastCPU = now;
        lastSysCPU = timeSample.tms_stime;
        lastUserCPU = timeSample.tms_utime;
    
        return percent;
    }

TODO: Інші платформи

Я б припустив, що частина коду Linux також працює для Unixes, за винятком частин, які читають псевдофайлову систему / proc. Можливо, на Unix ці частини можна замінити getrusage()і подібними функціями? Якщо хтось із ноу-хау Unix міг би відредагувати цю відповідь та заповнити деталі ?!


10
Попередження: у PdhAddCounter запит повинен бути локалізованим, інакше він запускатиметься лише на англомовній системі. Для системи Vista / 2008 та новіших версій віддайте перевагу використанню PdhAddEnglishCounter, щоб уникнути проблем із локалізацією.
моала

2
@NunoAniceto Під час використання PROCESS_MEMORY_COUNTERS, як ви отримуєте "Віртуальну пам'ять, яку зараз використовує поточний процес"? PrivateUsageне є членом PROCESS_MEMORY_COUNTERS- це помилка компілятора, яку я отримую!
CinCout

2
Чому ви використовуєте "quotes like these"для включення заголовків системи?
Гонки легкості на орбіті

8
@CinCout вам потрібен кастинг .. замініть GetProcessMemoryInfo (GetCurrentProcess (), & pmc, sizeof (pmc)); з GetProcessMemoryInfo (GetCurrentProcess (), (PROCESS_MEMORY_COUNTERS *) & pmc, sizeof (pmc));
Сумія

3
@Lanzelot Оскільки ми набагато вище Linux Kernel 3.0. Чи можете ви оновити відповідь Linux на POSIX API? Якщо можливо, також виправте відповідь Windows, замінивши GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));наGetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
Dr. Xperience

140

Mac OS X

Я сподівався знайти подібну інформацію і для Mac OS X. Оскільки його тут не було, я вийшов і викопав його сам. Ось деякі речі, які я знайшов. Якщо у когось є якісь інші пропозиції, я хотів би їх почути.

Загальна віртуальна пам'ять

Ця версія є складною для Mac OS X, оскільки вона не використовує попередньо встановлений розділ swap або файл, як Linux. Ось запис із документації Apple:

Примітка. На відміну від більшості операційних систем на базі Unix, Mac OS X не використовує попередньо розміщений розділ swap для віртуальної пам'яті. Натомість він використовує весь доступний простір на завантажувальній частині машини.

Отже, якщо ви хочете знати, скільки віртуальної пам’яті ще доступно, вам потрібно отримати розмір кореневого розділу. Ви можете зробити це так:

struct statfs stats;
if (0 == statfs("/", &stats))
{
    myFreeSwap = (uint64_t)stats.f_bsize * stats.f_bfree;
}

Всього зараз використовується віртуальний

Виклик systcl за допомогою клавіші "vm.swapusage" надає цікаву інформацію про використання swap:

sysctl -n vm.swapusage
vm.swapusage: total = 3072.00M  used = 2511.78M  free = 560.22M  (encrypted)

Мало того, що показник загального користування свопом, який відображається тут, може змінитися, якщо потрібно більше заміни, як пояснено у розділі вище. Таким чином, загальна сума є фактично поточною своп свопом. У C ++ ці дані можна запитувати таким чином:

xsw_usage vmusage = {0};
size_t size = sizeof(vmusage);
if( sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0)!=0 )
{
   perror( "unable to get swap usage by calling sysctlbyname(\"vm.swapusage\",...)" );
}

Зауважте, що "xsw_usage", оголошений у sysctl.h, здається, не задокументований, і я підозрюю, що існує більш портативний спосіб доступу до цих значень.

Зараз віртуальна пам'ять використовується моїм процесом

Ви можете отримати статистику вашого поточного процесу за допомогою task_infoфункції. Це включає поточний розмір резидента вашого процесу та поточний віртуальний розмір.

#include<mach/mach.h>

struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;

if (KERN_SUCCESS != task_info(mach_task_self(),
                              TASK_BASIC_INFO, (task_info_t)&t_info, 
                              &t_info_count))
{
    return -1;
}
// resident size is in t_info.resident_size;
// virtual size is in t_info.virtual_size;

Загальна доступна оперативна пам’ять

Об'єм фізичної оперативної пам’яті, доступної у вашій системі, доступний за допомогою такої sysctlфункції системи:

#include <sys/types.h>
#include <sys/sysctl.h>
...
int mib[2];
int64_t physical_memory;
mib[0] = CTL_HW;
mib[1] = HW_MEMSIZE;
length = sizeof(int64_t);
sysctl(mib, 2, &physical_memory, &length, NULL, 0);

В даний час використовується оперативна пам’ять

Ви можете отримати загальну статистику пам'яті за допомогою host_statisticsсистемної функції.

#include <mach/vm_statistics.h>
#include <mach/mach_types.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>

int main(int argc, const char * argv[]) {
    vm_size_t page_size;
    mach_port_t mach_port;
    mach_msg_type_number_t count;
    vm_statistics64_data_t vm_stats;

    mach_port = mach_host_self();
    count = sizeof(vm_stats) / sizeof(natural_t);
    if (KERN_SUCCESS == host_page_size(mach_port, &page_size) &&
        KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO,
                                        (host_info64_t)&vm_stats, &count))
    {
        long long free_memory = (int64_t)vm_stats.free_count * (int64_t)page_size;

        long long used_memory = ((int64_t)vm_stats.active_count +
                                 (int64_t)vm_stats.inactive_count +
                                 (int64_t)vm_stats.wire_count) *  (int64_t)page_size;
        printf("free memory: %lld\nused memory: %lld\n", free_memory, used_memory);
    }

    return 0;
}

Тут слід зазначити, що в Mac OS X є п'ять типів сторінок пам'яті. Вони такі:

  1. Провідні сторінки, які зафіксовані на місці і їх неможливо замінити
  2. Активні сторінки, які завантажуються у фізичну пам'ять, і їх було б досить важко замінити
  3. Неактивні сторінки, завантажені в пам'ять, але останнім часом не використовуються і можуть взагалі не знадобитися. Це потенційні кандидати для заміни. Цю пам’ять, напевно, потрібно було б розмити.
  4. Кешовані сторінки, які кешировані, імовірно, будуть легко використані. Кешована пам'ять, ймовірно, не потребує промивання. Поки можна кеш-сторінки повторно активувати
  5. Безкоштовні сторінки, які повністю безкоштовні та готові до використання.

Добре зауважити, що тільки тому, що Mac OS X може часом показувати дуже мало фактичної вільної пам'яті, це може бути не гарним показником того, скільки готово використовувати в короткий термін.

Оперативна пам’ять, яку зараз використовує мій процес

Дивіться "Віртуальну пам'ять, яку зараз використовує мій процес" вище. Цей же код застосовується.


Ви залишили #include <mach / mach.h>, щоб визначити task_info () у розділі "Віртуальна пам'ять, яку зараз використовує мій процес". Цей заголовок потрібно включити для визначення цієї функції.
Dan Nissenbaum

4
Будь-яка ідея щодо використання процесора?
Міхір Мехта

@Michael Taylor, це велике спасибі, але питання щодо оперативної пам’яті, яка зараз використовується для OS X, виявляється, ви отримуєте статистику VM, а не фізичну пам'ять. Це насправді так?
Едгар Арутьонійський

1
Як ми можемо обчислити APP-пам'ять та кеш-пам'ять, як монітор активності? Я використовував vm_stats.inactive_page_count * page_size t для обчислення кешу FIle, але він не синхронізується з монітором активності. Заздалегідь дякую
Аміт Ханделваль

1
оригінальний автор, мабуть, плутається з приводу «віртуальної пам’яті» - в деяких контекстах вона не стосується пам’яті, розміщеної на диску, а віртуальної простори адрес, яка може бути не повністю заповнена. Знайдіть систему, яка не використовує жодного свопу, і ви побачите, що більшість процесів мають більший розмір "virt", ніж розмір "rss". У розділі "Віртуальна пам'ять, яку зараз використовує мій процес", саме до цього "віртуальної пам'яті" відноситься - адресний простір, а не обмін пам'яттю на диску.
Пірс

63

Linux

У Linux ця інформація доступна у файловій системі / proc. Я не є великим прихильником використовуваного формату текстових файлів, оскільки, здається, кожен дистрибутив Linux налаштовує принаймні один важливий файл. Швидкий погляд на джерело "ps" виявляє безлад.

Але ось де ви шукаєте інформацію, яку шукаєте:

/ proc / meminfo містить більшість загальносистемної інформації, яку ви шукаєте. Ось це виглядає як у моїй системі; Я думаю, що вас цікавить MemTotal , MemFree , SwapTotal і SwapFree :

Anderson cxc # more /proc/meminfo
MemTotal:      4083948 kB
MemFree:       2198520 kB
Buffers:         82080 kB
Cached:        1141460 kB
SwapCached:          0 kB
Active:        1137960 kB
Inactive:       608588 kB
HighTotal:     3276672 kB
HighFree:      1607744 kB
LowTotal:       807276 kB
LowFree:        590776 kB
SwapTotal:     2096440 kB
SwapFree:      2096440 kB
Dirty:              32 kB
Writeback:           0 kB
AnonPages:      523252 kB
Mapped:          93560 kB
Slab:            52880 kB
SReclaimable:    24652 kB
SUnreclaim:      28228 kB
PageTables:       2284 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   4138412 kB
Committed_AS:  1845072 kB
VmallocTotal:   118776 kB
VmallocUsed:      3964 kB
VmallocChunk:   112860 kB
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

Для використання процесора вам доведеться трохи попрацювати. Linux надає загальне використання процесора з моменту запуску системи; це, мабуть, не те, що вас цікавить. Якщо ви хочете знати, яке використання процесора було за останню секунду чи 10 секунд, то вам потрібно запитати інформацію та обчислити її самостійно.

Інформація доступна в / proc / stat , що досить добре зафіксовано на веб- сайті http://www.linuxhowtos.org/System/procstat.htm ; ось як це виглядає на моїй 4-х ядерній коробці:

Anderson cxc #  more /proc/stat
cpu  2329889 0 2364567 1063530460 9034 9463 96111 0
cpu0 572526 0 636532 265864398 2928 1621 6899 0
cpu1 590441 0 531079 265949732 4763 351 8522 0
cpu2 562983 0 645163 265796890 682 7490 71650 0
cpu3 603938 0 551790 265919440 660 0 9040 0
intr 37124247
ctxt 50795173133
btime 1218807985
processes 116889
procs_running 1
procs_blocked 0

По-перше, потрібно визначити, скільки процесорів (або процесорів, або ядер обробки) доступні в системі. Для цього підрахуйте кількість записів 'cpuN', де N починається з 0 і кроком. Не рахуйте рядок 'cpu', який є комбінацією ліній cpuN. У моєму прикладі ви можете бачити cpu0 до cpu3, ​​для всього 4 процесорів. Відтепер ви можете ігнорувати cpu0..cpu3 та зосереджуватися лише на рядку 'cpu'.

Далі, ви повинні знати, що четверте число в цих рядках є мірою простою, і, отже, четверте число в рядку 'cpu' - ​​це загальний час очікування для всіх процесорів з часу завантаження. Цей час вимірюється в "джифсах" Linux, які становлять 1/100 секунди.

Але вам не байдуже загальний час простою; Ви дбаєте про час простою в заданому періоді, наприклад, останню секунду. Для того, щоб обчислити це, вам потрібно прочитати цей файл двічі, за 1 секунду. Тоді ви можете зробити диференцію четвертого значення рядка. Наприклад, якщо ви берете пробу і отримуєте:

cpu  2330047 0 2365006 1063853632 9035 9463 96114 0

Потім через секунду ви отримуєте цей зразок:

cpu  2330047 0 2365007 1063854028 9035 9463 96114 0

Відніміть два числа, і ви отримаєте різницю 396, це означає, що ваш процесор простояв 3,96 секунди за останні 1,00 секунди. Трюк, звичайно, полягає в тому, що вам потрібно розділити кількість процесорів. 3,96 / 4 = 0,99, і ваш відсоток простою; 99% простоює і 1% зайнято.

У своєму коді у мене буфер дзвінка з 360 записів, і я читаю цей файл щосекунди. Це дозволяє мені швидко обчислити використання процесора протягом 1 секунди, 10 секунд тощо, аж до 1 години.

Для інформації, що стосується певного процесу, потрібно заглянути в / proc / pid ; якщо вам не байдуже описуватись, ви можете заглянути в / proc / self.

Процесор, який використовується вашим процесом, доступний у / proc / self / stat . Це дивний файл, що складається з одного рядка; наприклад:

19340 (whatever) S 19115 19115 3084 34816 19115 4202752 118200 607 0 0 770 384 2
 7 20 0 77 0 266764385 692477952 105074 4294967295 134512640 146462952 321468364
8 3214683328 4294960144 0 2147221247 268439552 1276 4294967295 0 0 17 0 0 0 0

Важливими даними тут є 13-й та 14-й жетони (0 та 770 тут). 13-й маркер - це кількість jiffies, які процес виконав у користувальницькому режимі, а 14-й - кількість jiffies, які процес виконав у режимі ядра. Додайте їх разом, і ви отримаєте загальне використання процесора.

Знову вам доведеться періодично вибирати цей файл та обчислювати різницю для того, щоб визначити використання процесора в процесі використання.

Редагувати: пам’ятайте, що при обчисленні використання процесора вашого процесу ви повинні враховувати 1) кількість потоків у вашому процесі та 2) кількість процесорів у системі. Наприклад, якщо ваш однопотоковий процес використовує лише 25% ЦП, це може бути добре чи погано. Хороший для однопроцесорної системи, але поганий для 4-процесорної системи; це означає, що ваш процес працює постійно і використовує 100% доступних для нього циклів процесора.

Для інформації, що залежить від процесу, потрібно переглянути / proc / self / status, який виглядає приблизно так:

Name:   whatever
State:  S (sleeping)
Tgid:   19340
Pid:    19340
PPid:   19115
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 256
Groups: 0 1 2 3 4 6 10 11 20 26 27
VmPeak:   676252 kB
VmSize:   651352 kB
VmLck:         0 kB
VmHWM:    420300 kB
VmRSS:    420296 kB
VmData:   581028 kB
VmStk:       112 kB
VmExe:     11672 kB
VmLib:     76608 kB
VmPTE:      1244 kB
Threads:        77
SigQ:   0/36864
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: fffffffe7ffbfeff
SigIgn: 0000000010001000
SigCgt: 20000001800004fc
CapInh: 0000000000000000
CapPrm: 00000000ffffffff
CapEff: 00000000fffffeff
Cpus_allowed:   0f
Mems_allowed:   1
voluntary_ctxt_switches:        6518
nonvoluntary_ctxt_switches:     6598

Ці записи цікаві:

  • VmPeak - максимальний простір віртуальної пам’яті, що використовується процесом, в кБ (1024 байти).
  • VmSize - це поточний простір віртуальної пам'яті, що використовується процесом, в кБ. У моєму прикладі він досить великий: 651 352 кБ, або близько 636 мегабайт.
  • VmRss - це обсяг пам'яті, відображений у адресний простір процесу, або його розмір резидента. Це значно менше (420,296 кБ, або близько 410 мегабайт). Різниця: моя програма зіставила 636 Мб через mmap (), але отримала доступ до неї лише 410 Мб, і таким чином було призначено лише 410 Мб сторінок.

Єдиний предмет, про який я не впевнений - це Swapspace, який зараз використовується в моєму процесі . Я не знаю, чи є така можливість.


1
Дякую Мартіне, якби я мав всю цю інформацію, зібрану в одному місці, це врятувало б мені пару безсонних ночей ... Однак для процесора поточного процесу я думаю, що функція times () - це простіший і надійніший підхід. BTW: Зміна поточного процесу = VmSize - VmRSS, чи не так?
Ланселот

14

у Windows ви можете отримати використання процесора за кодом нижче:

#include <windows.h>
#include <stdio.h>

    //------------------------------------------------------------------------------------------------------------------
    // Prototype(s)...
    //------------------------------------------------------------------------------------------------------------------
    CHAR cpuusage(void);

    //-----------------------------------------------------
    typedef BOOL ( __stdcall * pfnGetSystemTimes)( LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime );
    static pfnGetSystemTimes s_pfnGetSystemTimes = NULL;

    static HMODULE s_hKernel = NULL;
    //-----------------------------------------------------
    void GetSystemTimesAddress()
    {
        if( s_hKernel == NULL )
        {   
            s_hKernel = LoadLibrary( L"Kernel32.dll" );
            if( s_hKernel != NULL )
            {
                s_pfnGetSystemTimes = (pfnGetSystemTimes)GetProcAddress( s_hKernel, "GetSystemTimes" );
                if( s_pfnGetSystemTimes == NULL )
                {
                    FreeLibrary( s_hKernel ); s_hKernel = NULL;
                }
            }
        }
    }
    //----------------------------------------------------------------------------------------------------------------

    //----------------------------------------------------------------------------------------------------------------
    // cpuusage(void)
    // ==============
    // Return a CHAR value in the range 0 - 100 representing actual CPU usage in percent.
    //----------------------------------------------------------------------------------------------------------------
    CHAR cpuusage()
    {
        FILETIME               ft_sys_idle;
        FILETIME               ft_sys_kernel;
        FILETIME               ft_sys_user;

        ULARGE_INTEGER         ul_sys_idle;
        ULARGE_INTEGER         ul_sys_kernel;
        ULARGE_INTEGER         ul_sys_user;

        static ULARGE_INTEGER    ul_sys_idle_old;
        static ULARGE_INTEGER  ul_sys_kernel_old;
        static ULARGE_INTEGER  ul_sys_user_old;

        CHAR  usage = 0;

        // we cannot directly use GetSystemTimes on C language
        /* add this line :: pfnGetSystemTimes */
        s_pfnGetSystemTimes(&ft_sys_idle,    /* System idle time */
            &ft_sys_kernel,  /* system kernel time */
            &ft_sys_user);   /* System user time */

        CopyMemory(&ul_sys_idle  , &ft_sys_idle  , sizeof(FILETIME)); // Could been optimized away...
        CopyMemory(&ul_sys_kernel, &ft_sys_kernel, sizeof(FILETIME)); // Could been optimized away...
        CopyMemory(&ul_sys_user  , &ft_sys_user  , sizeof(FILETIME)); // Could been optimized away...

        usage  =
            (
            (
            (
            (
            (ul_sys_kernel.QuadPart - ul_sys_kernel_old.QuadPart)+
            (ul_sys_user.QuadPart   - ul_sys_user_old.QuadPart)
            )
            -
            (ul_sys_idle.QuadPart-ul_sys_idle_old.QuadPart)
            )
            *
            (100)
            )
            /
            (
            (ul_sys_kernel.QuadPart - ul_sys_kernel_old.QuadPart)+
            (ul_sys_user.QuadPart   - ul_sys_user_old.QuadPart)
            )
            );

        ul_sys_idle_old.QuadPart   = ul_sys_idle.QuadPart;
        ul_sys_user_old.QuadPart   = ul_sys_user.QuadPart;
        ul_sys_kernel_old.QuadPart = ul_sys_kernel.QuadPart;

        return usage;
    }
    //------------------------------------------------------------------------------------------------------------------
    // Entry point
    //------------------------------------------------------------------------------------------------------------------
    int main(void)
    {
        int n;
        GetSystemTimesAddress();
        for(n=0;n<20;n++)
        {
            printf("CPU Usage: %3d%%\r",cpuusage());
            Sleep(2000);
        }
        printf("\n");
        return 0;
    }

чи можна це змінити для зовнішньої функції DLL, яку я можу пізніше зателефонувати в c #?
Ніко

11
Форматування usage =- це найкреативніше, що я бачив за якийсь час, і зовсім не читабельне, але креативне
ViRuSTriNiTy

Попередження: вираз у наведеному вище коді, який обчислює "використання", є вихідним. Якби система не працювала, вона ділиться на нуль. У випадку, якщо час простою дорівнював часу користувача + ядро, він виробить 0, а не 50%, як можна було б очікувати.
Андрій Білогорцефф

Також майте на увазі, що згідно з поточним MSDN, час ядра також включає час простою!
Андрій Білогорцефф

@sayyedmohsenzahraee: Я не розглядав логіку цього, а лише коментар до самого коду. 1) Використовуйте звичайні 64-бітні змінні замість об'єднання, тобто ULONGLONGдля VS замість ULARGE_INTEGER. 2) Ви надмірно ускладнюєте речі, телефонуючи CopyMemory(), просто робіть ULONGLONG ul_sys_idle = *(ULONGLONG*)&ft_sys_idle;замість цього. Він буде переведений в єдину інструкцію щодо процесора mov(або lea).
ahmd0

12

Linux

Портативний спосіб читання пам'яті та завантаження номерів - це sysinfoдзвінок

Використання

   #include <sys/sysinfo.h>

   int sysinfo(struct sysinfo *info);

ОПИС

   Until Linux 2.3.16, sysinfo() used to return information in the
   following structure:

       struct sysinfo {
           long uptime;             /* Seconds since boot */
           unsigned long loads[3];  /* 1, 5, and 15 minute load averages */
           unsigned long totalram;  /* Total usable main memory size */
           unsigned long freeram;   /* Available memory size */
           unsigned long sharedram; /* Amount of shared memory */
           unsigned long bufferram; /* Memory used by buffers */
           unsigned long totalswap; /* Total swap space size */
           unsigned long freeswap;  /* swap space still available */
           unsigned short procs;    /* Number of current processes */
           char _f[22];             /* Pads structure to 64 bytes */
       };

   and the sizes were given in bytes.

   Since Linux 2.3.23 (i386), 2.3.48 (all architectures) the structure
   is:

       struct sysinfo {
           long uptime;             /* Seconds since boot */
           unsigned long loads[3];  /* 1, 5, and 15 minute load averages */
           unsigned long totalram;  /* Total usable main memory size */
           unsigned long freeram;   /* Available memory size */
           unsigned long sharedram; /* Amount of shared memory */
           unsigned long bufferram; /* Memory used by buffers */
           unsigned long totalswap; /* Total swap space size */
           unsigned long freeswap;  /* swap space still available */
           unsigned short procs;    /* Number of current processes */
           unsigned long totalhigh; /* Total high memory size */
           unsigned long freehigh;  /* Available high memory size */
           unsigned int mem_unit;   /* Memory unit size in bytes */
           char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding to 64 bytes */
       };

   and the sizes are given as multiples of mem_unit bytes.

3

QNX

Оскільки це як "вікі-сторінка коду", я хочу додати якийсь код із бази знань QNX (зауважте: це не моя робота, але я перевірив це, і він прекрасно працює в моїй системі):

Як отримати використання процесора у%: http://www.qnx.com/support/knowledgebase.html?id=50130000000P9b5

#include <atomic.h>
#include <libc.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/iofunc.h>
#include <sys/neutrino.h>
#include <sys/resmgr.h>
#include <sys/syspage.h>
#include <unistd.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/debug.h>
#include <sys/procfs.h>
#include <sys/syspage.h>
#include <sys/neutrino.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <devctl.h>
#include <errno.h>

#define MAX_CPUS 32

static float Loads[MAX_CPUS];
static _uint64 LastSutime[MAX_CPUS];
static _uint64 LastNsec[MAX_CPUS];
static int ProcFd = -1;
static int NumCpus = 0;


int find_ncpus(void) {
    return NumCpus;
}

int get_cpu(int cpu) {
    int ret;
    ret = (int)Loads[ cpu % MAX_CPUS ];
    ret = max(0,ret);
    ret = min(100,ret);
    return( ret );
}

static _uint64 nanoseconds( void ) {
    _uint64 sec, usec;
    struct timeval tval;
    gettimeofday( &tval, NULL );
    sec = tval.tv_sec;
    usec = tval.tv_usec;
    return( ( ( sec * 1000000 ) + usec ) * 1000 );
}

int sample_cpus( void ) {
    int i;
    debug_thread_t debug_data;
    _uint64 current_nsec, sutime_delta, time_delta;
    memset( &debug_data, 0, sizeof( debug_data ) );

    for( i=0; i<NumCpus; i++ ) {
        /* Get the sutime of the idle thread #i+1 */
        debug_data.tid = i + 1;
        devctl( ProcFd, DCMD_PROC_TIDSTATUS,
        &debug_data, sizeof( debug_data ), NULL );
        /* Get the current time */
        current_nsec = nanoseconds();
        /* Get the deltas between now and the last samples */
        sutime_delta = debug_data.sutime - LastSutime[i];
        time_delta = current_nsec - LastNsec[i];
        /* Figure out the load */
        Loads[i] = 100.0 - ( (float)( sutime_delta * 100 ) / (float)time_delta );
        /* Flat out strange rounding issues. */
        if( Loads[i] < 0 ) {
            Loads[i] = 0;
        }
        /* Keep these for reference in the next cycle */
        LastNsec[i] = current_nsec;
        LastSutime[i] = debug_data.sutime;
    }
    return EOK;
}

int init_cpu( void ) {
    int i;
    debug_thread_t debug_data;
    memset( &debug_data, 0, sizeof( debug_data ) );
/* Open a connection to proc to talk over.*/
    ProcFd = open( "/proc/1/as", O_RDONLY );
    if( ProcFd == -1 ) {
        fprintf( stderr, "pload: Unable to access procnto: %s\n",strerror( errno ) );
        fflush( stderr );
        return -1;
    }
    i = fcntl(ProcFd,F_GETFD);
    if(i != -1){
        i |= FD_CLOEXEC;
        if(fcntl(ProcFd,F_SETFD,i) != -1){
            /* Grab this value */
            NumCpus = _syspage_ptr->num_cpu;
            /* Get a starting point for the comparisons */
            for( i=0; i<NumCpus; i++ ) {
                /*
                * the sutime of idle thread is how much
                * time that thread has been using, we can compare this
                * against how much time has passed to get an idea of the
                * load on the system.
                */
                debug_data.tid = i + 1;
                devctl( ProcFd, DCMD_PROC_TIDSTATUS, &debug_data, sizeof( debug_data ), NULL );
                LastSutime[i] = debug_data.sutime;
                LastNsec[i] = nanoseconds();
            }
            return(EOK);
        }
    }
    close(ProcFd);
    return(-1);
}

void close_cpu(void){
    if(ProcFd != -1){
        close(ProcFd);
        ProcFd = -1;
    }
}

int main(int argc, char* argv[]){
    int i,j;
    init_cpu();
    printf("System has: %d CPUs\n", NumCpus);
    for(i=0; i<20; i++) {
        sample_cpus();
        for(j=0; j<NumCpus;j++)
        printf("CPU #%d: %f\n", j, Loads[j]);
        sleep(1);
    }
    close_cpu();
}

Як отримати безкоштовну (!) Пам’ять: http://www.qnx.com/support/knowledgebase.html?id=50130000000mlbx

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <err.h>
#include <sys/stat.h>
#include <sys/types.h>

int main( int argc, char *argv[] ){
    struct stat statbuf;
    paddr_t freemem;
    stat( "/proc", &statbuf );
    freemem = (paddr_t)statbuf.st_size;
    printf( "Free memory: %d bytes\n", freemem );
    printf( "Free memory: %d KB\n", freemem / 1024 );
    printf( "Free memory: %d MB\n", freemem / ( 1024 * 1024 ) );
    return 0;
} 

1

Mac OS X - процесор

Загальне використання процесора:

З Отримати системну інформацію на MacOS X? :

#include <mach/mach_init.h>
#include <mach/mach_error.h>
#include <mach/mach_host.h>
#include <mach/vm_map.h>

static unsigned long long _previousTotalTicks = 0;
static unsigned long long _previousIdleTicks = 0;

// Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
// You'll need to call this at regular intervals, since it measures the load between
// the previous call and the current one.
float GetCPULoad()
{
   host_cpu_load_info_data_t cpuinfo;
   mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
   if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpuinfo, &count) == KERN_SUCCESS)
   {
      unsigned long long totalTicks = 0;
      for(int i=0; i<CPU_STATE_MAX; i++) totalTicks += cpuinfo.cpu_ticks[i];
      return CalculateCPULoad(cpuinfo.cpu_ticks[CPU_STATE_IDLE], totalTicks);
   }
   else return -1.0f;
}

float CalculateCPULoad(unsigned long long idleTicks, unsigned long long totalTicks)
{
  unsigned long long totalTicksSinceLastTime = totalTicks-_previousTotalTicks;
  unsigned long long idleTicksSinceLastTime  = idleTicks-_previousIdleTicks;
  float ret = 1.0f-((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime)/totalTicksSinceLastTime : 0);
  _previousTotalTicks = totalTicks;
  _previousIdleTicks  = idleTicks;
  return ret;
}

0

Для Linux Ви також можете використовувати / proc / self / statm, щоб отримати єдиний рядок чисел, що містять ключову інформацію про оперативну пам'ять, що є швидшою обробкою, ніж перегляд довгого списку повідомленої інформації при отриманні від proc / self / status

Див. Http://man7.org/linux/man-pages/man5/proc.5.html

   /proc/[pid]/statm
          Provides information about memory usage, measured in pages.
          The columns are:

              size       (1) total program size
                         (same as VmSize in /proc/[pid]/status)
              resident   (2) resident set size
                         (same as VmRSS in /proc/[pid]/status)
              shared     (3) number of resident shared pages (i.e., backed by a file)
                         (same as RssFile+RssShmem in /proc/[pid]/status)
              text       (4) text (code)
              lib        (5) library (unused since Linux 2.6; always 0)
              data       (6) data + stack
              dt         (7) dirty pages (unused since Linux 2.6; always 0)

1
Хтось знає, наскільки надійний загальний розмір, який повідомляється на сторінках? Це фактичний слід у пам’яті на сторінках?
niken

-1

Я використовував наступний код у своєму проекті C ++, і він працював чудово:

static HANDLE self;
static int numProcessors;
SYSTEM_INFO sysInfo;

double percent;

numProcessors = sysInfo.dwNumberOfProcessors;

//Getting system times information
FILETIME SysidleTime;
FILETIME SyskernelTime; 
FILETIME SysuserTime; 
ULARGE_INTEGER SyskernelTimeInt, SysuserTimeInt;
GetSystemTimes(&SysidleTime, &SyskernelTime, &SysuserTime);
memcpy(&SyskernelTimeInt, &SyskernelTime, sizeof(FILETIME));
memcpy(&SysuserTimeInt, &SysuserTime, sizeof(FILETIME));
__int64 denomenator = SysuserTimeInt.QuadPart + SyskernelTimeInt.QuadPart;  

//Getting process times information
FILETIME ProccreationTime, ProcexitTime, ProcKernelTime, ProcUserTime;
ULARGE_INTEGER ProccreationTimeInt, ProcexitTimeInt, ProcKernelTimeInt, ProcUserTimeInt;
GetProcessTimes(self, &ProccreationTime, &ProcexitTime, &ProcKernelTime, &ProcUserTime);
memcpy(&ProcKernelTimeInt, &ProcKernelTime, sizeof(FILETIME));
memcpy(&ProcUserTimeInt, &ProcUserTime, sizeof(FILETIME));
__int64 numerator = ProcUserTimeInt.QuadPart + ProcKernelTimeInt.QuadPart;
//QuadPart represents a 64-bit signed integer (ULARGE_INTEGER)

percent = 100*(numerator/denomenator);

Ви не отримали за цим механізмом такі значення, як 0,00% та значення, що перевищують 100%?
Буддхіка Чатуранга

Це для Mac OS?
RuLoViC

@RuLoViC Це для Windows.
непрямокутний
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.