【问题标题】:How can I calculate the running time of a pthread matrix multiplication program?如何计算 pthread 矩阵乘法程序的运行时间?
【发布时间】:2013-04-05 07:13:57
【问题描述】:

我创建了一个矩阵乘法程序,一个是串行的,一个是使用 pthreads 的。我需要比较他们的运行时间。我的序列代码需要大约 16 秒来计算 1000x1000 矩阵乘法,我用秒表检查了它,它应该是正确的。另一方面,当我运行我的 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;
}

【问题讨论】:

    标签: c time matrix pthreads matrix-multiplication


    【解决方案1】:

    我知道的最简单的方法是使用 OpenMP。与 -fopenmp 链接

    #include <omp.h>
    
    int main() {
        double dtime = omp_get_wtime(); //value in seconds
        //run some code
        dtime = omp_get_wtime() - dtime;
    

    }

    请注意,16 秒的 1000x1000 矩阵乘法非常慢。我的代码在 4.3 GHz 的 i7-2600k 上在 0.03 秒内完成了 1056x1056,甚至还不到最大理论速度的 30%。

    【讨论】:

    • 我在我的 OpenMP 矩阵乘法代码中使用了上述方法,效果很好。另一方面,我的串行 C 代码在 2.4GHz 的 i5 中花费了大约 16 秒,而且我使用的是 O(n^3) 的简单算法。我只是没有做任何优化和/或使用更好的算法。
    【解决方案2】:

    这是获取已用 CPU 时间的方法,但不是获取已用挂钟时间的方法。为此,您将希望使用time(只有第二个粒度)或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 秒)。

    【讨论】:

    • 我猜在您的示例中,您想在最后几行中键入 begin 和 end 而不是 finish 或 start,对吗?如果我留下这样的代码,我会得到未声明的错误。如果我将它们更改为开始和结束并编译,则会收到以下错误:mmnew.c:(.text+0x38e): undefined reference to `clock_gettime'
    • 您需要将 -lrt 添加到您为clock_gettime 链接到的库列表中。我将此添加到答案中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    相关资源
    最近更新 更多