之前使用的是在一台机器上的,内存非常有限,而核心数也不是很多,为了减小机器承受的压力,每运行到某块*alloc出的内存必定不被使用时,就立即free掉,而在多机上,这样的压力分散到了多台机器上。按照这次作业的要求,需要让计算速度尽可能快,这样就应当能不free的尽量不free,能不同步的不做同步,从而快速得到结果,再去free申请来的内存。
程序中还有一些细节,如当j=0时,操作row_now[j]必定会比操作row_now[0]慢,因为对j的取值解析也需要一次访问内存,为了至高的速度考虑,程序中应尽量避免这样的浪费。
上次课时,何老师指出,不必要的calloc也是一种浪费,因为对内存的清空,即初始化全0,也是要耗费时间的。在个问题中这样做是冗余的,因此只需要在j=0时对其做赋值,而其它时候做+=操作。
另外,如果在for循环中只对游标等于某个数值时做if判断,是非常不值得的,因为if的条件判断也是要耗费时间的,所以这部分被我重构了。
注释中,用old:标注的是之前的做法和考虑,new:标注是新的做法和考虑。
/* 15121856 刘知昊 第2次作业(方阵x向量按行分配,计时) */ #include#include #include #include //方阵的维度 #define N 960000 time_t start,end;//开始和结束时间 int main() { int *vec=NULL;//列向量 //double *mat=NULL;//自己进程的那部分矩阵 int my_rank;//自己进程的进程号 int comm_sz;//总的进程数目 int my_row;//本进程处理的行数 int i,j;//通用游标 double *result=NULL;//用来存本进程计算出的结果向量 double *all_rst=NULL;//只给0号进程存总的结果 double *row_now=NULL;//每个进程每次仅申请的一行 /**********************/ MPI_Init(NULL,NULL); MPI_Comm_rank(MPI_COMM_WORLD,&my_rank); MPI_Comm_size(MPI_COMM_WORLD,&comm_sz); //计时开始 if(my_rank==0) { start=time(NULL); } //本进程处理的行数就是总阶数/进程数 my_row=N/comm_sz; //为每个进程都申请空间 vec=malloc(N*sizeof(int)); //mat=malloc(N*my_row*sizeof(double));//这是个进程每次申请完 row_now=malloc(N*sizeof(double));//这是每个进程每次仅申请一行 result=malloc(my_row*sizeof(double));//old:为了初始值置0而使用calloc //new:为了效率而用malloc,只要在i=0时做赋值 //向量的值的设定,使用memset会报错 for(j=0;j<n;j++) vec[j]="1;" 本行的值的设定="" 在实际使用时,这里是读入本进程应处理的下一行="" for(j="0;j 测试
因为有其他同学也在用,他们在做什么事会直接影响我测试出的时间,在4主机48进程下测试了三次,时间的单位是秒:
我试过,如果直接把上一次(没有做速度上的优化时)的代码-O3编译,然后4主机48进程下跑(也就是说单纯依赖核心数的增加,而不对代码做速度上的优化)时,这个时间是380秒左右,相比之下,依赖重构在速度上优化了一半左右的时间。
当然,对速度的追求,造成了内存的浪费。如果真的有OPT算法,那么内存的浪费也完全没有了(可惜只能想想)。