在做矩阵乘法并行化测试的时候,在利用<time.h>的clock()计时时出现了一点问题。
首先看串行的程序:
// matrix_cpu.c #include <stdio.h> #include <stdlib.h> #include <time.h> #define NUM 2048 void matrixMul(float *A, float *B, float *C, int M, int K, int N) { int i, j, k; for(i = 0; i < M; i++) { for(j = 0; j < N; j++) { float sum = 0.0f; for(k = 0; k < K; k++) { sum += A[i*k+k] * B[k*N+j]; } C[i*N+j] = sum; } } } int main(int argc, char* argv[]) { float *A, *B, *C; clock_t start, finish; double duration; A = (float *) malloc (sizeof(float) * NUM * NUM); B = (float *) malloc (sizeof(float) * NUM * NUM); C = (float *) malloc (sizeof(float) * NUM * NUM); memset(A, 0, sizeof(float) * NUM * NUM); memset(B, 0, sizeof(float) * NUM * NUM); memset(C, 0, sizeof(float) * NUM * NUM); printf("Start...\n"); start = clock(); matrixMul(A, B, C, NUM, NUM, NUM); finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf("Time: %fs\n", duration); return 0; }
在编译后,运行该程序,得到如下结果:
[wfshen@cu05 matrix]$ ./matrix_cpu Start... Time: 26.130000s
由于CPU是至强E5-2650,所以算得比较快(但目前仍然是串行,也就是说单核单线程),这样也要26秒了(在博主的i5-4200 ThinkPad上用时是171秒)。
加上time命令再运行一遍,结果如下:
[wfshen@cu05 matrix]$ time ./matrix_cpu Start... Time: 26.770000s real 0m28.073s user 0m26.779s sys 0m0.019s
可以看到,时间与程序中统计的差不多,实际执行时间由于加了malloc等的时间所以长了一点,但还是合情合理的。
那么,再来看并行的OpenMP程序:
#include <stdio.h> #include <stdlib.h> #include <time.h> #define NUM 2048 #define THREAD_NUM 2 void matrixMul(float *A, float *B, float *C, int M, int K, int N) { int i, j, k; #pragma omp parallel for private(j,k) num_threads(THREAD_NUM) for(i = 0; i < M; i++) { for(j = 0; j < N; j++) { float sum = 0.0f; #pragma ivdep for(k = 0; k < K; k++) { sum += A[i*k+k] * B[k*N+j]; } C[i*N+j] = sum; } } } int main(int argc, char* argv[]) { float *A, *B, *C; clock_t start, finish; double duration; A = (float *) malloc (sizeof(float) * NUM * NUM); B = (float *) malloc (sizeof(float) * NUM * NUM); C = (float *) malloc (sizeof(float) * NUM * NUM); memset(A, 0, sizeof(float) * NUM * NUM); memset(B, 0, sizeof(float) * NUM * NUM); memset(C, 0, sizeof(float) * NUM * NUM); printf("Start...\n"); start = clock(); matrixMul(A, B, C, NUM, NUM, NUM); finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf("Time: %fs\n", duration); return 0; }
可以看到,该OpenMP程序只使用了两个线程,那么运行时间理论上来说能减半。
在编译后,运行该程序,得到如下结果:
[wfshen@cu05 matrix]$ ./matrix_omp Start... Time: 26.550000s
这就奇怪了,明明心里面数了一下大概花了15秒,但是为什么计时还是26秒呢?
再加上time命令运行一遍:
[wfshen@cu05 matrix]$ time ./matrix_omp Start... Time: 26.440000s real 0m13.438s user 0m26.457s sys 0m0.016s
可以看到,实际的运行时间是13秒,但是user却超过了13秒,且几乎是real的两倍。
查了一下,发现了这样的解释:
real: 墙上时间,即程序从开启到结束的实际运行时间 user: 执行用户代码所花的实际时间(不包括内核调用),指进程执行所消耗的实际CPU时间 sys:该程序在内核调用上花的时间
在,单线程串行的时候,只有一个线程在运行,那么user所代表的就是一个cpu的时间。然而,当到多线程的情况下,一个进程可能有多个线程并行执行,但是user把所有的线程时间都加起来了,也就是算了一个总时间,这样,user的时间也就基本上等于单线程时的user时间。
这样,我们把线程数调到4,再运行代码(大概7秒):
[wfshen@cu05 matrix]$ ./matrix_omp Start... Time: 27.270000s [wfshen@cu05 matrix]$ time ./matrix_omp Start... Time: 27.170000s real 0m7.486s user 0m27.176s sys 0m0.018s
可以发现,实际运行时间7秒,CPU总时间27秒,差不多:
再把线程数调到16,再运行代码(大概2秒多):
[wfshen@cu05 matrix]$ ./matrix_omp Start... Time: 33.980000s [wfshen@cu05 matrix]$ time ./matrix_omp Start... Time: 33.530000s real 0m2.241s user 0m33.479s sys 0m0.075s
可以发现,CPU总时间有增加的趋势,不过实际时间还是大有减少。E5-2650是8核心16线程,再往上加线程时间反而会增长。
总结:在多线程的情况下,还是用time命令看时间吧。