2016-05-29 5 views
1

大きな行列の合計を計算したいと思います。現在、複数のスレッドまたは1つのスレッドを使用するとパフォーマンスの向上は見られません。私は、問題は誤った共有に関連していると思うが、私はまた私の構造体にパディングを追加した。見てください!パディングを使用した誤った共有の防止

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <time.h> 
#include <pthread.h> 

#define WIDTH 20000 
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER; 

struct split { // sizeof(split) = 24 
    int start; 
    int end; 
    int* matrix; 
    int i; 
    char padding[64 - 24]; //Padding the private sum variables  forces them into separate cache lines and removes false sharing. Assume cache line is 64 bytes 
}; 

int ran(){ 
    return rand() % 21; 
} 
int* createBigMatrix(){ 
    int* a = malloc(sizeof(int)* WIDTH * WIDTH); 
    for (int i = 0; i < WIDTH * WIDTH; i ++){ 
     a[i] = ran(); // fill up the matrix with random numbers 
    } 
    return a; 
} 
static int finalSum; 
void* partialSum(void* arg){ 
    struct split* a = arg; 
    int totalSum = 0; // create local variable 
    int i; 
    for (i = a->start; i <= a->end; i ++){ 
     totalSum += a->matrix[i]; 
    } 
    pthread_mutex_lock(&mylock); 
    finalSum += totalSum; // critical section 
    pthread_mutex_unlock(&mylock); 
    free(a); 

    return 0; 
} 
int main(){ //-294925289 
    int useMultiThreads = 1; // there is no difference between using one thread or 4 therads 
    finalSum = 0; 
    pthread_t thread_ids[4]; 
    // i want a square matrix of npages width 
    int* c = createBigMatrix(); 

    printf("%lu\n", sizeof(struct split)); 
    if (useMultiThreads){ 
     // split the tasks evenly amoung 4 threads 
     // since there are 20,000x20,000, there must be 400,000,000 cells 
     int start[] = {0, 100000000, 200000000, 300000000}; 
     int end[] = {99999999, 199999999, 299999999, 399999999}; 
     // calculate sum 
     for (int i = 0; i < 4; i ++){ 
      struct split* a = malloc(sizeof(struct split)); 
      a->start = start[i]; 
      a->end = end[i]; 
      a->matrix = c; 
      pthread_create(thread_ids + i, NULL, partialSum, a); 
     } 

     for (int i = 0; i < 4; i ++){ // join em up 
      pthread_join(thread_ids[i], NULL); 
     } 
    } 
    else { // use single thread 
     for (int i = 0; i <= 399999999; i ++){ 
      finalSum += c[i]; 
     } 
    } 

    printf("total sum is %d\n", finalSum); 
/* 
    real 0m4.871s 
    user 0m4.844s 
    sys  0m0.392s 
*/ 
    free(c); 
    return 0; 
} 
+2

スレッドによって使用される行列インデックスが重複せず、とにかくパラメータ構造体をパディングすることが役に立たないため、誤った共有の範囲があまりないように見えます。合計金額をどのように測定していますか?このプロセスの全体的なパフォーマンスは、集計が始まる前に巨大な配列を作成して読み込むことによって支配されるように思われます。 –

+1

あなたのインデックスには注意してください。 'int'は大きな行列のための正しい型ではありません。また、 'for'ループから' a-> 'を使用することも考慮してください。コンパイラーは '* a'がフードの下で変更されるかどうかを知ることができないため、各反復でリロードする必要があります。 'a'を修飾して' restrict'に変更することもできますが、単純にローカル変数に値(境界と行列)をロードしてループ内で使用する方が簡単です。 –

答えて

0

コードのパフォーマンスに関係していなければならない、私はあなたのstructのパディング一切表示されません。実際のデータは、指し示されている行列内にあります。

あなたの懸案事項、スピードアップの欠如は、おそらくあなたのコードが完全にメモリに束縛されているためです。つまり、合計を実行するには、メモリバスを介してメモリからデータをフェッチする必要があります。 (あなたの行列は大きすぎてキャッシュに収まらない)。つまり、あなたの計算は、すべてのコアで共有されるメモリバスの帯域幅に制限されます。

また、あなたのコードは、合計を行うことによって支配されるのではなく、プログラムのシーケンシャル部分にあるran()への呼び出しによって認識されます。

関連する問題