1

プログラムのスレッドを専用にして、そのパフォーマンスに関する指標を収集したいと考えています。メモリ使用量、CPU など。/proc/stat および /proc/pid/stat ファイルを使用してこれを実行しようとしています。私は現在、%CPU 使用率を測定しようとして立ち往生しています。私のプログラムによって報告された値は、「トップ」が報告しているものと完全に一致していません。いくつかの異なる Linux ディストリビューションでこれを試しましたが、それぞれで同じ結果が得られました。

これは、パーセンテージを計算するために使用しているコードです。誰でもここで問題を見つけることができますか?

https://github.com/mmcilroy/cpu_usage

#include <stdlib.h>
#include <sys/types.h>
#include <sys/times.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

struct pstat {
    long unsigned int utime_ticks;
    long int cutime_ticks;
    long unsigned int stime_ticks;
    long int cstime_ticks;
    long unsigned int vsize; // virtual memory size in bytes
    long unsigned int rss; //Resident  Set  Size in bytes
    long unsigned int cpu_total_time;
};

int get_usage(const pid_t pid, struct pstat* result) {

    //convert  pid to string
    char pid_s[20];
    snprintf(pid_s, sizeof(pid_s), "%d", pid);

    char stat_filepath[30] = "/proc/"; strncat(stat_filepath, pid_s,
            sizeof(stat_filepath) - strlen(stat_filepath) -1);
    strncat(stat_filepath, "/stat", sizeof(stat_filepath) -
            strlen(stat_filepath) -1);

    FILE *fpstat = fopen(stat_filepath, "r");
    if (fpstat == NULL) {
        perror("FOPEN ERROR ");
        return -1;
    }

    FILE *fstat = fopen("/proc/stat", "r");
    if (fstat == NULL) {
        perror("FOPEN ERROR ");
        fclose(fstat);
        return -1;
    }

    //read values from /proc/pid/stat
    bzero(result, sizeof(struct pstat));
    long int rss;
    if (fscanf(fpstat, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu"
                "%lu %ld %ld %*d %*d %*d %*d %*u %lu %ld",
                &result->utime_ticks, &result->stime_ticks,
                &result->cutime_ticks, &result->cstime_ticks, &result->vsize,
                &rss) == EOF) {
        fclose(fpstat);
        return -1;
    }
    fclose(fpstat);
    result->rss = rss * getpagesize();

    //read+calc cpu total time from /proc/stat
    long unsigned int cpu_time[10];
    bzero(cpu_time, sizeof(cpu_time));
    if (fscanf(fstat, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
                &cpu_time[0], &cpu_time[1], &cpu_time[2], &cpu_time[3],
                &cpu_time[4], &cpu_time[5], &cpu_time[6], &cpu_time[7],
                &cpu_time[8], &cpu_time[9]) == EOF) {
        fclose(fstat);
        return -1;
    }

    fclose(fstat);

    for(int i=0; i < 4;i++)
        result->cpu_total_time += cpu_time[i];

    printf( "usage: cpu %lu, utime %lu, stime %lu\n", result->cpu_total_time, result->utime_ticks, result->stime_ticks );

    return 0;
}

void calc_cpu_usage_pct(const struct pstat* cur_usage,
                        const struct pstat* last_usage,
                        double* usage)
{
    printf( "delta: cpu %lu, utime %lu, stime %lu\n",
        cur_usage->cpu_total_time - last_usage->cpu_total_time,
        cur_usage->utime_ticks - last_usage->utime_ticks,
        cur_usage->stime_ticks - last_usage->stime_ticks );

    const long unsigned int cpu_diff = cur_usage->cpu_total_time - last_usage->cpu_total_time;
    const long unsigned int pid_diff =
        ( cur_usage->utime_ticks + cur_usage->utime_ticks + cur_usage->stime_ticks - cur_usage->stime_ticks ) -
        ( last_usage->utime_ticks + last_usage->utime_ticks + last_usage->stime_ticks - last_usage->stime_ticks );

    *usage = 100.0 * ( (double)pid_diff / (double)cpu_diff );
}

int main( int argc, char* argv[] )
{
    pstat prev, curr;
    double pct;

    struct tms t;
    times( &t );

    if( argc <= 1 ) {
        printf( "please supply a pid\n" ); return 1;
    }

    while( 1 )
    {
        if( get_usage(atoi(argv[1]), &prev) == -1 ) {
            printf( "error\n" );
        }

        sleep( 5 );

        if( get_usage(atoi(argv[1]), &curr) == -1 ) {
            printf( "error\n" );
        }

        calc_cpu_usage_pct(&curr, &prev, &pct);

        printf("%%cpu: %.02f\n", pct);
    }
}

自分で試してみたい場合、プログラムは 1 つの引数 (監視するプロセスの pid) を期待します。

4

5 に答える 5

4

これは少し古いことは知っていますが、新しい方程式が機能する理由を説明できます。(1/INTERVAL) * (pid diff)

100 * (pid diff) / (cpu diff)これは、最初の例でやろうとしていたように見える、基本的なパーセンテージ方程式を単純化したものです。

/proc/stat の CPU 時間 (および /proc/pid/stat の utime と stime) は、USER_HZ (または jiffies) で報告されます。通常、この値は1/100 秒です。これは、CPU に対して毎秒 100 の「ティック」があることを意味します。つまり、「CPU diff」はINTERVAL*100.

それを代入すると、次のようになります。

100 * (pid 差分) / (間隔 * 100)

100 をキャンセルすると、次のものが残ります。

(pid 差分) / INTERVAL

これは、現在使用しているものと同じです。これはまた、上部のコードにある問題を実際に修正した場合、それも同様に機能するはずであることを意味します。pid diff は(curr utime + curr stime) - (prev utime + prev stime). うまくいかない場合は、CPU 時間を合計する方法が間違っている可能性がありますか? どのような値であるべきかを知っているので、テストするのは簡単です(INTERVAL*100)

これで作業方程式ができたので、元のコードの問題を理解する必要はないかもしれませんが、USER_HZ が1/100 でないシステムでそれを使用しようとすると、方程式が無効になることに注意してください。

于 2013-09-03T21:22:13.873 に答える
0

Linux でのこのコマンドは、Linux で役立つ場合があります。

# apt-get install sysstat
# up2date sysstat
# mpstat 

これで、コマンド ライン出力を文字列として取得し、解析する方法を見つける方法がわかります。mpstat のさまざまなパラメーターを使用することもできます。また、試してみてください$ top

このリンクからヘルプを入手してください。

于 2013-04-15T09:54:20.317 に答える
0

メインループは多少ずれています: "prev" を取得してからスリープし、次に "next" を取得して差を計算するのではなく、ループの外側で "prev" を取得し、ループの内側で "curr" を取得して計算し、 「curr」を「prev」にコピーしてから、もう一度ループします。これにより、使用時間の 50% がカウントされない部分が修正されます。

于 2013-04-15T10:01:36.570 に答える