簡體   English   中英

測量N倍於代碼塊執行時間的問題

[英]Problem measuring N times the execution time of a code block

編輯:我寫了這篇長篇文章,解釋了每個小細節后,才發現我的問題...如果有人可以給我關於我做錯了什么的好答案,以及如何以秒為單位獲取執行時間(使用5的浮點數小數點左右),我將其標記為接受。 提示:問題在於我如何解釋clock_getttime()手冊頁。

你好

假設我有一個名為myOperation的函數,該函數需要測量其執行時間。 來衡量它,我使用clock_gettime()因為它是推薦這里的評論之一。

我的老師建議我們對它進行N次測量,以便獲得最終報告的平均值,標准差和中位數。 他還建議我們執行myOperation M次而不是僅僅執行一次。 如果myOperation是一個非常快速的操作,則對其進行M次測量可以使我們對它所花費的“實時”有所了解; 因為所使用的時鍾可能不具有測量此類操作所需的精度。 因此,僅執行一次myOperation或執行M次實際上取決於操作本身是否花費了足夠的時間來達到我們正在使用的時鍾精度。

我在處理M次執行時遇到麻煩。 M增加會(最終)降低最終平均值。 這對我來說沒有意義。 就是這樣,從A點到B點平均需要3到5秒鍾。但是,從A到B再回到A 5次(這使它變成10倍,原因是A到B與B相同)。到A),然后進行測量。 乘以10所得的平均值應該與從A點到B點的平均值相同,即3到5秒。

這是我希望我的代碼執行的操作,但是它不起作用。 如果我不斷增加從A到B再回到A的次數,那么每次的平均值都會越來越低,這對我來說毫無意義。

理論足夠,這是我的代碼:

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

#define MEASUREMENTS 1
#define OPERATIONS   1

typedef struct timespec TimeClock;

TimeClock diffTimeClock(TimeClock start, TimeClock end) {
    TimeClock aux;

    if((end.tv_nsec - start.tv_nsec) < 0) {
        aux.tv_sec = end.tv_sec - start.tv_sec - 1;
        aux.tv_nsec = 1E9 + end.tv_nsec - start.tv_nsec;
    } else {
        aux.tv_sec = end.tv_sec - start.tv_sec;
        aux.tv_nsec = end.tv_nsec - start.tv_nsec;
    }

    return aux;
}

int main(void) {
    TimeClock sTime, eTime, dTime;
    int i, j;

    for(i = 0; i < MEASUREMENTS; i++) {
        printf(" » MEASURE %02d\n", i+1);

        clock_gettime(CLOCK_REALTIME, &sTime);

        for(j = 0; j < OPERATIONS; j++) {
            myOperation();
        }

        clock_gettime(CLOCK_REALTIME, &eTime);

        dTime = diffTimeClock(sTime, eTime);

        printf("   - NSEC (TOTAL): %ld\n", dTime.tv_nsec);
        printf("   - NSEC (OP): %ld\n\n", dTime.tv_nsec / OPERATIONS);
    }

    return 0;
}

注意:上面的diffTimeClock函數來自此博客文章 我用myOperation()替換了我的真實操作,因為發布我的真實函數沒有任何意義,因為我不得不發布較長的代碼塊,如果需要,您可以輕松地編寫myOperation()並進行編譯你希望。

如您所見, OPERATIONS = 1 ,結果為:

 » MEASURE 01
   - NSEC (TOTAL): 27456580
   - NSEC (OP): 27456580

對於OPERATIONS = 100 ,結果為:

 » MEASURE 01
   - NSEC (TOTAL): 218929736
   - NSEC (OP): 2189297

對於OPERATIONS = 1000 ,結果為:

 » MEASURE 01
   - NSEC (TOTAL): 862834890
   - NSEC (OP): 862834

對於OPERATIONS = 10000 ,結果為:

 » MEASURE 01
   - NSEC (TOTAL): 574133641
   - NSEC (OP): 57413

現在,我不是一個數學天才,實際距離還很遠,但這對我來說毫無意義。 我已經和一個與我一起參與這個項目的朋友談論過這個問題,他也無法理解它們之間的區別。 我不明白為什么增加OPERATIONS價值會越來越低。 該操作本身應該花費相同的時間(當然,平均來說,不是完全相同的時間),無論我執行多少次。

您可以告訴我,這實際上取決於操作本身,所讀取的數據以及某些數據可能已經在高速緩存中,等等,但是我不認為這是問題所在。 就我而言, myOperation正在從CSV文件讀取5000行文本,並用;分隔值; 並將這些值插入數據結構。 對於每次迭代,我都會破壞數據結構並再次對其進行初始化。

現在我想到了,我還認為使用clock_gettime()測量時間存在問題,也許我沒有正確使用它。 我的意思是,看最后一個示例,其中OPERATIONS = 10000 它花費的總時間為574133641ns,大約為0.5s。 那是不可能的,花了幾分鍾,因為我不能忍受看着屏幕等待着去吃點東西。

看起來TimeClock類型有兩個字段,一個字段用於秒,另一個字段用於納秒。 僅將納秒級場除以操作數是沒有意義的。 您需要除以總時間。

如果您使用的是帶有gettimeofday()函數的POSIX系統,則可以使用類似這樣的方法來獲取當前時間(以微秒為單位):

long long timeInMicroseconds(void) {
    struct timeval tv;

    gettimeofday(&tv,NULL);
    return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
}

這非常方便的原因是,為了計算函數占用的空間,您需要執行以下操作:

long long start = timeInMicroseconds();
... do your task N times ...
printf("Total microseconds: %lld", timeInMicroseconds()-start);

因此,您不必處理兩個整數,一個處理秒數,一個處理微秒。 增加和減少時間將以明顯的方式起作用。

您只需要更改diffTimeClock()函數即可將差值秒數返回為double

double diffTimeClock(TimeClock start, TimeClock end) {
    double diff;

    diff = (end.tv_nsec - start.tv_nsec) / 1E9;
    diff += (end.tv_sec - start.tv_sec);

    return diff;
}

並在主例程dTime更改為double ,並將printfs更改為適合:

printf("   - SEC (TOTAL): %f\n", dTime);
printf("   - SEC (OP): %f\n\n", dTime / OPERATIONS);

我通常為此使用time()函數。 它顯示了掛鍾時間,但實際上這是我最后要關心的。

性能測試的一個難題是操作系統可能會緩存文件系統相關的操作。 因此,第二次(及以后)運行可能比第一次運行快得多。 通常,您需要測試可能的操作並取平均結果,以便對所做的任何更改的結果有良好的感覺。 變量太多,可以幫助您濾除噪聲。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM