3

行列乗算プログラムを作成しました。1 つはシリアルで、もう 1 つは pthreads を使用しています。実行時間を比較する必要があります。私のシリアル コードは、1000x1000 行列の乗算を計算するのに約 16 秒かかります。ストップウォッチを使用して確認したところ、正確に正しい値になっています。一方、pthreads 行列乗算プログラムを実行すると、結果として約 22 ~ 23 秒で出力されますが、結果は端末に非常に高速に出力されます。また、ストップウォッチを使用して実行時間を出力するのにかかる時間を確認したところ、約 6 秒でしたが、約 23 秒かかったことが出力されます。pthread プログラムの実行時間をチェックするには、別の方法があると思います。以下に、私の pthreads コードを示します。

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

int SIZE, NTHREADS;
int **A, **B, **C;

void init()
{
    int i, j;

    A = (int**)malloc(SIZE * sizeof(int *));
    for(i = 0; i < SIZE; i++)
        A[i] = malloc(SIZE * sizeof(int));

    B = (int**)malloc(SIZE * sizeof(int *));
    for(i = 0; i < SIZE; i++)
        B[i] = malloc(SIZE * sizeof(int));

    C = (int**)malloc(SIZE * sizeof(int *));
    for(i = 0; i < SIZE; i++)
        C[i] = malloc(SIZE * sizeof(int));

    srand(time(NULL));

    for(i = 0; i < SIZE; i++) {
        for(j = 0; j < SIZE; j++) {
            A[i][j] = rand()%100;
            B[i][j] = rand()%100;
        }
    }
}

void mm(int tid)
{
    int i, j, k;
    int start = tid * SIZE/NTHREADS;
    int end = (tid+1) * (SIZE/NTHREADS) - 1;

    for(i = start; i <= end; i++) {
        for(j = 0; j < SIZE; j++) {
            C[i][j] = 0;
            for(k = 0; k < SIZE; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

void *worker(void *arg)
{
    int tid = (int)arg;
    mm(tid);
}

int main(int argc, char* argv[])
{
    pthread_t* threads;
    int rc, i;

    if(argc != 3)
    {
        printf("Usage: %s <size_of_square_matrix> <number_of_threads>\n", argv[0]);
        exit(1);
    }

    SIZE = atoi(argv[1]);
    NTHREADS = atoi(argv[2]);
    init();
    threads = (pthread_t*)malloc(NTHREADS * sizeof(pthread_t));

    clock_t begin, end;
    double time_spent;


    begin = clock();

    for(i = 0; i < NTHREADS; i++) {
        rc = pthread_create(&threads[i], NULL, worker, (void *)i);
        assert(rc == 0);
    }

    for(i = 0; i < NTHREADS; i++) {
        rc = pthread_join(threads[i], NULL);
        assert(rc == 0);
    } 

    end = clock();

    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("Elapsed time: %.2lf seconds.\n", time_spent);

    for(i = 0; i < SIZE; i++)
        free((void *)A[i]);
    free((void *)A);

    for(i = 0; i < SIZE; i++)
        free((void *)B[i]);
    free((void *)B);

    for(i = 0; i < SIZE; i++)
        free((void *)C[i]);
    free((void *)C);

    free(threads);

    return 0;
}
4

2 に答える 2

2

これは、経過した CPU 時間を取得する方法ですが、経過したウォールクロック時間を取得する方法ではありません。そのためには、どちらかtime(2 番目の粒度しかない)を使用するかclock_gettimeCLOCK_MONOTONICオプションと共に使用することをお勧めします。これには、POSIX リアルタイム拡張 (-lrt) に対してリンクする必要があります。

struct timespec begin, end;
double elapsed;

clock_gettime(CLOCK_MONOTONIC, &begin);

// spawn threads to do work here

clock_gettime(CLOCK_MONOTONIC, &end);

elapsed = end.tv_sec - begin.tv_sec;
elapsed += (end.tv_nsec - begin.tv_nsec) / 1000000000.0;

あなたの例では、約4つのスレッドを使用したと思いますか? CPU 時間は、(CPU 1 で使用された時間 + CPU 2 で使用された時間 + CPU 3 で使用された時間 + CPU 4 で使用された時間) になり、絶対時間の約 4 倍 (6 対 23 秒) になります。

于 2013-04-12T17:03:22.400 に答える
1

私が知っている最も簡単な方法は、OpenMP を使用することです。-fopenmp でリンク

#include <omp.h>

int main() {
    double dtime = omp_get_wtime(); //value in seconds
    //run some code
    dtime = omp_get_wtime() - dtime;

}

1000x1000 行列乗算の 16 秒は非常に遅いことに注意してください。私のコードは、4.3 GHz の i7-2600k で 0.03 秒で 1056x1056 を実行しますが、それでも理論上の最大速度の 30% 未満です。

于 2013-04-13T15:04:49.650 に答える