7

Как определить потребление ЦП и памяти изнутри процесса

1

Описание проблемы: Получение параметров производительности в работающем приложении

У меня возникла задача определить следующие параметры производительности изнутри работающего приложения:

  • Общая доступная виртуальная память
  • Виртуальная память, в настоящее время используемая системой
  • Виртуальная память, используемая моим процессом
  • Общая доступная оперативная память (RAM)
  • Оперативная память, в настоящее время используемая системой
  • Оперативная память, используемая моим процессом
  • Процент использования ЦП в данный момент
  • Процент использования ЦП, используемого моим процессом

Код должен был работать как на Windows, так и на Linux. Несмотря на то, что на первый взгляд это кажется стандартной задачей, поиск необходимой информации в документации (WIN32 API, GNU docs), а также в Интернете занял у меня несколько дней. Я столкнулся с огромным количеством неполной, неверной и устаревшей информации по этой теме.

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

5 ответ(ов)

8

Windows

Некоторые из приведённых значений легко доступны через соответствующий Win32 API, и я просто перечисляю их здесь для полноты картины. Однако для получения других значений необходимо использовать библиотеку Performance Data Helper (PDH), которая может показаться несколько "неинтуитивной" и требует много проб и ошибок, чтобы начать работать. (По крайней мере, у меня ушло много времени, возможно, я просто не очень смышленый...)

Примечание: Для ясности весь код проверки ошибок опущен. Обязательно проверяйте коды возврата...!

  • Общая виртуальная память:

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

    Примечание: Название "TotalPageFile" может сбивать с толку. На самом деле этот параметр даёт "Размер виртуальной памяти", который включает размер файла подкачки плюс установленную оперативную память.

  • Используемая виртуальная память:

    Такой же код, как и для "Общей виртуальной памяти", а затем

    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;
    
  • Используемая физическая память:

    Такой же код, как и для "Общей виртуальной памяти", а затем

    DWORDLONG physMemUsed = memInfo.ullTotalPhys - memInfo.ullAvailPhys;
    
  • Используемая физическая память текущим процессом:

    Такой же код, как и для "Используемой виртуальной памяти текущим процессом", а затем

    SIZE_T physMemUsedByMe = pmc.WorkingSetSize;
    
  • Использование CPU в данный момент:

    #include "TCHAR.h"
    #include "pdh.h"
    
    static PDH_HQUERY cpuQuery;
    static PDH_HCOUNTER cpuTotal;
    
    void init(){
        PdhOpenQuery(NULL, NULL, &cpuQuery);
        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;
    }
    
  • Использование CPU текущим процессом:

    #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 очевидным на первый взгляд выбором было использование API POSIX, таких как getrusage() и т.д. Я потратил некоторое время, пытаясь заставить это работать, но так и не получил значимых значений. Когда я наконец проверил исходный код ядра, я обнаружил, что эти API, видимо, ещё не полностью реализованы в версии ядра Linux 2.6!?

В итоге я получил все значения с помощью комбинации чтения из псевдо-файловой системы /proc и вызовов ядра.

  • Общая виртуальная память:

    #include "sys/types.h"
    #include "sys/sysinfo.h"
    
    struct sysinfo memInfo;
    
    sysinfo (&memInfo);
    long long totalVirtualMem = memInfo.totalram;
    totalVirtualMem += memInfo.totalswap;
    totalVirtualMem *= memInfo.mem_unit;
    
  • Используемая виртуальная память:

    Такой же код, как и для "Общей виртуальной памяти", а затем

    long long virtualMemUsed = memInfo.totalram - memInfo.freeram;
    virtualMemUsed += memInfo.totalswap - memInfo.freeswap;
    virtualMemUsed *= memInfo.mem_unit;
    
  • Используемая виртуальная память текущим процессом:

    #include "stdlib.h"
    #include "stdio.h"
    #include "string.h"
    
    int parseLine(char* line){
        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(){ //Примечание: это значение в Кб!
        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;
    totalPhysMem *= memInfo.mem_unit;
    
  • Используемая физическая память:

    Такой же код, как и для "Общей виртуальной памяти", а затем

    long long physMemUsed = memInfo.totalram - memInfo.freeram;
    physMemUsed *= memInfo.mem_unit;
    
  • Используемая физическая память текущим процессом:

    Измените функцию getValue() в "Используемой виртуальной памяти текущим процессом", следующим образом:

    int getValue(){ //Примечание: это значение в Кб!
        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;
    }
    
  • Использование CPU в данный момент:

    #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){
            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;
    }
    
  • Использование CPU текущим процессом:

    #include "stdlib.h"
    #include "stdio.h"
    #include "string.h"
    #include "sys/times.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){
            percent = -1.0; // Обнаружение переполнения. Просто пропустите
    
1

Вопрос: Как получить информацию о виртуальной и физической памяти на Mac OS X?

Ответ:

Получить информацию о виртуальной и физической памяти на Mac OS X можно несколькими способами. Однако стоит отметить, что в отличие от Linux, Mac OS X не использует предустановленное разделение подкачки; вместо этого он использует всё доступное пространство на загрузочном разделе. Ниже приведены различные методы для получения информации о памяти.

Общая виртуальная память

Чтобы узнать, сколько виртуальной памяти доступно, можно получить размер корневого раздела:

#include <sys/statvfs.h>

struct statfs stats;
if (0 == statfs("/", &stats))
{
    uint64_t myFreeSwap = (uint64_t)stats.f_bsize * stats.f_bfree;
    // Теперь myFreeSwap содержит доступное пространство
}

Объём текущей используемой виртуальной памяти

Вы можете получить информацию о использовании подкачки через sysctl с использованием ключа "vm.swapusage":

sysctl -n vm.swapusage

Это выдаст общую информацию о подкачке, например:

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

В C++ это можно запросить следующим образом:

#include <sys/sysctl.h>

xsw_usage vmusage = {0};
size_t size = sizeof(vmusage);
if (sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0) != 0)
{
   perror("Не удалось получить информацию о использовании подкачки");
}

Используемая виртуальная память для процесса

Информацию о текущем процессе можно получить с помощью функции 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;
}
// t_info.resident_size содержит размер в памяти;
// 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;
size_t length = sizeof(int64_t);
sysctl(mib, 2, &physical_memory, &length, NULL, 0);

Текущая используемая RAM

Общие статистические данные о памяти можно получить с помощью функции host_statistics:

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

mach_port_t mach_port = mach_host_self();
vm_statistics64_data_t vm_stats;
mach_msg_type_number_t count = sizeof(vm_stats) / sizeof(natural_t);

if (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)vm_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)vm_size;
    printf("Свободная память: %lld\nИспользуемая память: %lld\n", free_memory, used_memory);
}

Важно

На Mac OS X существует пять типов страниц памяти:

  1. Заблокированные (Wired) страницы, которые нельзя выгнать.
  2. Активные (Active) страницы, загруженные в физическую память.
  3. Неактивные (Inactive) страницы, которые были загружены, но не используются.
  4. Кэшированные (Cached) страницы, которые могут быть легко повторно использованы.
  5. Свободные (Free) страницы, полностью свободные и готовые к использованию.

Следует помнить, что даже если Mac OS X показывает очень маленькое количество свободной памяти, это не всегда указывает на то, сколько памяти можно использовать в краткосрочной перспективе.

Таким образом, для получения информации о памяти на Mac OS X существует множество методов и подходов, и каждый из них может быть полезен в зависимости от ваших нужд.

0

В Linux эта информация доступна в файловой системе /proc. Я не сильно люблю текстовый формат, который используется, так как каждое дистрибутив Linux, похоже, настраивает как минимум один важный файл. Однако вот где можно найти интересующую вас информацию:

/proc/meminfo содержит большинство системных данных, которые вам нужны. Вот что у меня на системе; я думаю, вас интересуют MemTotal, MemFree, SwapTotal и SwapFree:

MemTotal:      4083948 kB
MemFree:       2198520 kB
Buffers:         82080 kB
Cached:        1141460 kB
SwapTotal:     2096440 kB
SwapFree:      2096440 kB

Что касается использования ЦП, здесь потребуется немного поработать. Linux предоставляет информацию о всём использовании CPU с момента запуска системы; это, вероятно, не то, что вас интересует. Если вы хотите узнать, каким было использование ЦП за последнюю секунду или десять секунд, вам нужно будет запрашивать эту информацию и вычислять её самостоятельно.

Эта информация доступна в /proc/stat, что довольно хорошо задокументировано на http://www.linuxhowtos.org/System/procstat.htm; вот как это выглядит на моем 4-ядерном компьютере:

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

Во-первых, вам нужно определить, сколько ЦП (или процессоров, или вычислительных ядер) доступно в системе. Для этого сосчитайте количество записей ‘cpuN’, где N начинается с 0 и увеличивается. Не учитывайте строку 'cpu', которая является комбинацией строк cpuN. В моем примере видны cpu0 по cpu3, итого 4 процессора. Теперь вы можете игнорировать cpu0..cpu3 и сосредоточиться только на строке 'cpu'.

Далее, вам нужно знать, что четвертое число в этих строках является измерением времени простоя, и, следовательно, четвертое число в строке 'cpu' - это общее время простоя для всех процессоров с момента загрузки. Это время измеряется в "jiffies" в 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; если вам не важен ваш pid, вы можете взглянуть в /proc/self.

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

19340 (whatever) S 19115 19115 3084 34816 19115 4202752 118200 607 ...

Важные данные здесь — это 13-й и 14-й токены (0 и 770 в данном случае). 13-й токен — это количество jiffies, которое процесс использовал в пользовательском режиме, а 14-й — в режиме ядра. Складываете оба значения, и вы получаете общее использование ЦП.

Снова вам придется периодически считывать этот файл и вычислять разницу, чтобы определить использование ЦП процессом со временем.

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

Что касается информации о памяти, специфичной для процесса, нужно смотреть в /proc/self/status, который выглядит так:

Name:   whatever
State:  S (sleeping)
Tgid:   19340
Pid:    19340
PPid:   19115
...
VmPeak:   676252 kB
VmSize:   651352 kB
VmRSS:    420296 kB
...

Интересующие вас записи, начинающиеся с 'Vm':

  • VmPeak — максимальный объем виртуальной памяти, используемой процессом, в кБ (1024 байт).
  • VmSize — текущий объем виртуальной памяти, используемой процессом, в кБ.
  • VmRSS — объем памяти, который был сопоставлен в адресное пространство процесса, или его резидентный набор.

Единственное, что я не уверен, это используемое место под файл подкачки процессом. Не знаю, доступна ли эта информация.

0

На Windows вы можете получить загрузку процессора с помощью следующего кода:

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

//------------------------------------------------------------------------------------------------------------------
// Прототип(ы)... 
//------------------------------------------------------------------------------------------------------------------
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)
// ==============
// Возвращает значение типа CHAR в диапазоне от 0 до 100, представляющее текущую загрузку процессора в процентах.
//----------------------------------------------------------------------------------------------------------------
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;

    // Прямо использовать GetSystemTimes в языке C нельзя
    /* Добавьте эту строку :: pfnGetSystemTimes */
    s_pfnGetSystemTimes(&ft_sys_idle,    /* Время простоя системы */
        &ft_sys_kernel,  /* Время ядра системы */
        &ft_sys_user);   /* Время пользователя системы */

    CopyMemory(&ul_sys_idle  , &ft_sys_idle  , sizeof(FILETIME)); // Могло бы быть оптимизировано...
    CopyMemory(&ul_sys_kernel, &ft_sys_kernel, sizeof(FILETIME)); // Могло бы быть оптимизировано...
    CopyMemory(&ul_sys_user  , &ft_sys_user  , sizeof(FILETIME)); // Могло бы быть оптимизировано...

    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;
}

//------------------------------------------------------------------------------------------------------------------
// Точка входа
//------------------------------------------------------------------------------------------------------------------
int main(void)
{
    int n;
    GetSystemTimesAddress();
    for(n=0; n<20; n++)
    {
        printf("Загрузка процессора: %3d%%\r", cpuusage());
        Sleep(2000);
    }
    printf("\n");
    return 0;
}

Этот код использует функцию GetSystemTimes из библиотеки Kernel32.dll, чтобы получить время простоя, времени ядра и времени пользователя системы. На основе этих значений рассчитывается процент загрузки процессора. В main функция запускается в цикле, который печатает значение загрузки процессора каждые 2 секунды.

0

Как получить использование процессора в процентах на QNX

Если вы ищете способ получения использования процессора в процентах на QNX, вот код из базы знаний QNX, который работает на моем устройстве. Обратите внимание, что это не моя работа, но я проверял это и оно функционально.

Ссылка на источник: Как получить использование процессора

#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++) {
        /* Получаем время sutime для потока простоев #i+1 */
        debug_data.tid = i + 1;
        devctl(ProcFd, DCMD_PROC_TIDSTATUS, &debug_data, sizeof(debug_data), NULL);
        /* Получаем текущее время */
        current_nsec = nanoseconds();
        /* Получаем разности между текущим и последним значениями */
        sutime_delta = debug_data.sutime - LastSutime[i];
        time_delta = current_nsec - LastNsec[i];
        /* Вычисляем загрузку */
        Loads[i] = 100.0 - ((float)(sutime_delta * 100) / (float)time_delta);
        if(Loads[i] < 0) {
            Loads[i] = 0;
        }
        /* Сохраняем для следующего цикла */
        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));
    /* Открываем подключение к proc для общения. */
    ProcFd = open("/proc/1/as", O_RDONLY);
    if(ProcFd == -1) {
        fprintf(stderr, "pload: Не удается получить доступ к 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) {
            /* Сохраняем это значение */
            NumCpus = _syspage_ptr->num_cpu;
            /* Получаем начальную точку для сравнений */
            for(i = 0; i < NumCpus; i++) {
                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("В системе: %d процессоров\n", NumCpus);
    for(i = 0; i < 20; i++) {
        sample_cpus();
        for(j = 0; j < NumCpus; j++)
            printf("Процессор #%d: %f\n", j, Loads[j]);
        sleep(1);
    }
    close_cpu();
}

Как получить свободную (!) память на QNX

Если вам нужно узнать, сколько свободной памяти доступно на QNX, вы можете использовать следующий пример кода. Также это демонстрирует простоту работы с системными вызовами.

Ссылка на источник: Как получить свободную память

#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("Свободная память: %d байт\n", freemem);
    printf("Свободная память: %d КБ\n", freemem / 1024);
    printf("Свободная память: %d МБ\n", freemem / (1024 * 1024));
    return 0;
}

Эти примеры кода помогут вам просто и эффективно получить необходимые данные о загрузке процессора и свободной памяти в системе QNX.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь