2011-05-10 24 views
4

是否有任何可靠的方法如何在程序運行時測量其CPU利用率?我可能不得不使用time.h的POSIX clock()函數。這個想法首先使用一些毫秒來設置一個空閒的CPU負載(步驟A),然後設置完整的CPU負載(步驟B),然後不斷啓動一個程序並調用clock()。因此,我可以計算相對於在步驟A和步驟B中計算出的CPU利用率,以便監測百分比中的CPU利用率。我假定所有其他後臺進程都被忽略。如何在運行時使用POSIX clock()函數監視CPU利用率?

但是,我不確定如何實現這些步驟A和步驟B,說空閒()和full_load()函數只使用C89和POSIX?

+0

您是在測量您正在使用的進程的CPU利用率,還是單獨的進程? – Spudd86 2011-05-10 13:31:00

+0

@ Spudd86:我自己的過程 – psihodelia 2011-05-10 13:32:30

回答

5

當你說「full_load」,並且你只需要一個CPU或負載下的虛擬內核時,一個簡單的緊密循環就可以實現。當然,它不會使用芯片上的所有晶體管(也就是說,我們不是在談論「滿載」的老化測試),但是它將在預定的時間片上獲得CPU ,使用所有可用的時鐘週期,而沒有系統調用會放棄對內核的控制,並可能導致執行的線程被重新調度以備後用。你也可以使用帶有信號處理器的報警器來退出循環。所以這可以讓你運行循環大約一秒鐘的執行時間(警報不完全是時間精確的......它們靠近,但不是時鐘週期)。

此外,對於「閒置」負載部分,您可以做同樣的事情,但使用sigsuspend()而不是緊密的循環,這將等待警報消失。

所以,你的代碼可能類似於以下內容:

#include <signal.h> 
#include <unistd.h> 
#include <time.h> 
#include <stdio.h> 

static sig_atomic_t alarm_flag = 1; 

void alarm_handler(int arg) 
{ 
    alarm_flag = 0; 
} 

clock_t idle() 
{ 
    //setup the alarm flag 
    alarm_flag = 1; 

    //setup the signal masks 
    sigset_t old_signal_set; 
    sigset_t new_signal_set; 

    sigemptyset(&old_signal_set); 
    sigemptyset(&new_signal_set); 

    //block the alarm signal 
    sigaddset(&new_signal_set, SIGALRM); 
    sigprocmask(SIG_BLOCK, &new_signal_set, &old_signal_set); 

    //setup the alarm 
    alarm(1); 

    clock_t time_before = clock(); 

    //sit idle while we wait for the alarm to go off 
    while(alarm_flag) 
     sigsuspend(&old_signal_set); 

    clock_t time_after = clock(); 

    //restore the old signal mask 
    sigprocmask(SIG_SETMASK, &old_signal_set, NULL); 

    return time_after - time_before; 
} 

clock_t full_load() 
{ 
    //set the alarm signal 
    alarm_flag = 1; 

    //set the 1-second alarm 
    alarm(1); 

    clock_t time_before = clock(); 

    //loop until the alarm goes off 
    while(alarm_flag); 

    clock_t time_after = clock(); 

    return time_after - time_before; 
} 

int main() 
{ 
    //setup the signal handler for the alarm 
    sigset(SIGALRM, alarm_handler); 

    //call the functions 
    clock_t idle_time = idle(); 
    clock_t load_time = full_load(); 

    //... do whatever else you need to-do with this info 
    printf("Idle Time: %d\n", (int)idle_time); 
    printf("Load Time: %d\n", (int)load_time); 

    return 0; 
} 

請記住,根據POSIX標準,應該是每秒一個百萬個時鐘的時基爲的clock_t值,所以你應該看到「full_load」返回的數字接近該數字,因爲我們正在「滿載」大約一秒鐘。空閒負載應該非常小(當然)。我在我的Mac Pro的生成這裏的數字:

Idle Time: 31 
Load Time: 1000099 

這樣似乎有點在線與你在找什麼,只要知道時鐘多少個週期還是可以看到clock()返回。我當然會多次運行這個數據,並以平均值來更好地顯示您可能會看到的差異。

2

我認爲這包括在clock_gettime(2)的linux上CLOCK_VIRTUAL(BSD/HP-UX)或CLOCK_PROCESS_CPUTIME_ID。

+0

你不是指'CLOCK_PROCESS_CPUTIME_ID' – Spudd86 2011-05-10 16:39:27

+0

不,我的意思是CLOCK_VIRTUAL。顯然你只能依靠[SusV2](http://pubs.opengroup.org/onlinepubs/007908799/xsh/clock_gettime.html)計算CLOCK_REALTIME,並且我在看BSD並選擇了錯誤的。 Linux使用您的常量,HP-UX也使用CLOCK_VIRTUAL。編輯答案。 – Mel 2011-05-10 17:03:08

0

您不指定POSIX的版本,但如果您使用的是C89,則它必須非常舊。 POSIX.1-2001 aka SUSv3需要C99,還有POSIX.1-2008。

校準似乎沒有必要;只是比較返回到單調(更好,但可能不可用)或掛鐘時間的值。對於clock(),請使用CLOCKS_PER_SEC define(如果系統支持XSI選項,則保證爲100萬,但如果僅爲POSIX,則保證爲100萬)。

考慮getrusage()而不是clock()以獲得更高的準確性和靈活性。

功能getrusage()在早期的POSIX版本的XSI選項下;更改歷史記錄稱它是在第4版第2版(SUSv1)中引入的,並且已移至第5期(SUSv2)中的基礎,但其上仍有XSI標記。在任何情況下,它都是4.2BSD的功能。

另一個選項是times()函數。