2017-02-15 25 views
1

我正在嘗試測量線程切換開銷時間。 我有兩個線程,一個共享變量,一個互斥鎖和兩個條件變量。兩個線程會來回切換,將1或0寫入共享變量。這是衡量線程上下文切換開銷的正確解決方案嗎?

我假設pthread_cond_wait(& cond,&互斥量)等待時間大約等於2 x線程上下文切換時間。因爲如果一個thread1必須等待一個條件變量,它必須放棄互斥鎖到thread2->thread2 context switch - > thread2執行它的任務併發信號通知條件變量喚醒第一個線程 - >上下文切換回線程1 - > thread1重新獲取鎖。

我的假設是否正確?

我的代碼如下:

#include <sys/types.h> 
#include <wait.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <sys/resource.h> 
#include <dirent.h> 
#include <ctype.h> 
#include<signal.h> 
#include <stdio.h> 
#include <stdint.h> 
#include <time.h> 
#include <pthread.h> 


int var = 0; 

int setToZero = 1; 

int count = 5000; 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 

pthread_cond_t isZero = PTHREAD_COND_INITIALIZER; 

pthread_cond_t isOne = PTHREAD_COND_INITIALIZER; 


struct timespec firstStart; 

unsigned long long timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p) 
{ 
    return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) - 
      ((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec); 
} 

void* thread1(void* param) 
{ 

    int rc; 
    struct timespec previousStart; 
    struct timespec start; //start timestamp 
    struct timespec stop; //stop timestamp 
    unsigned long long result; 
    int idx = 0; 
    int measurements[count]; 
    clock_gettime(CLOCK_MONOTONIC, &stop); 

    result = timespecDiff(&stop,&firstStart); 

    printf("first context-switch time:%llu\n", result); 

    clock_gettime(CLOCK_MONOTONIC, &previousStart); 

    while(count > 0){ 

    //acquire lock 
    rc = pthread_mutex_lock(&mutex); 

    clock_gettime(CLOCK_MONOTONIC,&start); 

    while(setToZero){ 
    pthread_cond_wait(&isOne,&mutex); // use condition variables so the threads don't busy wait inside local cache 
    } 

    clock_gettime(CLOCK_MONOTONIC,&stop); 


    var = 0; 

    count--; 

    setToZero = 1; 

    //printf("in thread1\n"); 

    pthread_cond_signal(&isZero); 
    //end of critical section 
    rc = pthread_mutex_unlock(&mutex); //release lock 

    result = timespecDiff(&stop,&start); 

    measurements[idx] = result; 

    idx++; 
} 

result = 0; 

int i = 0; 
while(i < idx) 
{ 
    result += measurements[i++]; 
} 

result = result /(2*idx); 

printf("thread1 result: %llu\n",result); 
} 


void* thread2(void* param) 
{ 
    int rc; 
    struct timespec previousStart; 
    struct timespec start; //start timestamp 
    struct timespec stop; //stop timestamp 
    unsigned long long result; 
    int idx = 0; 
    int measurements[count]; 

    while(count > 0){ 

    //acquire lock 
    rc = pthread_mutex_lock(&mutex); 

    clock_gettime(CLOCK_MONOTONIC,&start); 

    while(!setToZero){ 
    pthread_cond_wait(&isZero,&mutex); 
    } 

    clock_gettime(CLOCK_MONOTONIC,&stop); 

    var = 1; 

    count--; 

    setToZero = 0; 

    //printf("in thread2\n"); 

    pthread_cond_signal(&isOne); 
    //end of critical section 
    rc = pthread_mutex_unlock(&mutex); //release lock 

    result = timespecDiff(&stop,&start); 

    measurements[idx] = result; 

    idx++; 
    } 

result = 0; 

int i = 0; 
while(i < idx) 
{ 
    result += measurements[i++]; 
} 

result = result /(2*idx); 

printf("thread2 result: %llu\n",result); 
} 

int main(){ 
    pthread_t threads[2]; 

    pthread_attr_t attr; 

    pthread_attr_init(&attr); 

    clock_gettime(CLOCK_MONOTONIC,&firstStart); 

    pthread_create(&threads[0],&attr,thread1,NULL); 

    pthread_create(&threads[1],&attr,thread2,NULL); 

    printf("waiting...\n"); 

    pthread_join(threads[0],NULL); 

    pthread_join(threads[1],NULL); 

    pthread_cond_destroy(&isOne); 

    pthread_cond_destroy(&isZero); 

} 

我得到以下時間:

first context-switch time:144240 
thread1 result: 3660 
thread2 result: 3770 
+0

除非您只有一個CPU內核,否則在這種情況下,線程可能不需要上下文切換*。 – EOF

+0

我正在使用單核心機器 – JJTO

+0

然後有一個事實,即有其他進程/線程要求cpu時間。上下文切換是狀態變量等的加載/卸載,我不認爲你可以測量它,你甚至可能遭受觀察者的影響:)操作系統負責上下文切換,在用戶空間中你不需要控制它,這一切都發生在你的進程正在睡覺。 –

回答

0

你說:

我假設調用pthread_cond_wait(& COND,&互斥)等待時間大約等於2個線程上下文切換時間。

這不是一個有效的假設。一旦釋放了互斥鎖,這會通知內核,然後它必須喚醒另一個線程。例如,如果有其他線程在等待運行,它可能不會立即做到這一點。互斥 - 正如其名稱所示 - 保證當事情發生時不會發生。它不會保證他們什麼時候會。

你不能指望從一個進程內可靠地測量上下文切換,並且肯定不會使用Posix API,因爲沒有任何承諾會這樣做。

  • 在Linux上,你可以計數上下文切換使用/proc/[pid]/status進程或線程。

  • 在Windows上,此信息可從Performance Monitor API獲取。

無論是這些都會讓你走向你的目標,我不知道。我懷疑你真正想知道的是使用多線程系統會影響性能,但這需要你測量整個應用程序的性能。

相關問題