一、Linux操作系统的学习
1.1 Linux下C编程
1.2 Linux 进程
1.3 Shell入门
超算习堂 - Shell入门教程
(记录不小心贴在进程的后面了,内容基本都是上一次学习过的)
1.4 Shell编程作业
SHELL1 统计文件的行数
编写一个shell脚本以输出一个文本文件 a.txt 中的行数
#!/bin/bash
wc -l < a.txt
运行:
yang@yang-virtual-machine:~/桌面/shellwork$ vim shell1.sh
yang@yang-virtual-machine:~/桌面/shellwork$ vim a.txt
yang@yang-virtual-machine:~/桌面/shellwork$ chmod +x ./shell1.sh
yang@yang-virtual-machine:~/桌面/shellwork$ ./shell1.sh
9
SHELL2 打印文件的最后5行
查看日志的时候,经常会从文件的末尾往前查看,请编写一个shell脚本以输出一个文本文件 a.txt 中的 最后5行。
#!/bin/bash
tail -5 a.txt
运行:
yang@yang-virtual-machine:~/桌面/shellwork$ vim shell2.sh
yang@yang-virtual-machine:~/桌面/shellwork$ chmod +x ./shell2.sh
yang@yang-virtual-machine:~/桌面/shellwork$ ./shell2.sh
int a = 10;
int b = 100;
cout << "a + b:" << a + b << endl;
return 0;
}
SHELL3 监控CPU使用率
编写shell脚本,实现对后台CPU使用率的的监控,并将CPU利用率前三的进程信息存储到文件中。
#!/bin/bash
ps -aux --sort=-pcpu | head -4 >>cpu3.txt
运行:
yang@yang-virtual-machine:~/桌面$ vim cpu.sh
yang@yang-virtual-machine:~/桌面$ ./cpu.sh
bash: ./cpu.sh: 权限不够
yang@yang-virtual-machine:~/桌面$ chmod +x ./cpu.sh
yang@yang-virtual-machine:~/桌面$ ./cpu.sh
yang@yang-virtual-machine:~/桌面$ vim cpu3.txt
cpu3.txt内容:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
yang 19504 0.5 0.7 408156 31604 ? SNsl 21:16 0:00 /usr/libexec/tracker-extract-3
yang 19335 0.4 1.6 651096 66120 ? Ssl 21:08 0:02 /usr/libexec/gnome-terminal-server
yang 1241 0.3 6.7 4500040 270416 ? Ssl 19:11 0:29 /usr/bin/gnome-shell
二、入门并行编程理论学习
1. OpenMP
2.向量化(先了解)
向量化指令集: Mirror of Intel® Intrinsics Guide (laruence.com)
3.并行编程方法论(先了解)
观看了三个视频
三、实操优化代码
1.矩阵乘法优化
将ijk的顺序调换成ikj,然后进行并行
#pragma omp parallel for shared(a,b,c) schedule(dynamic)
for(int i=1;i<N;i++)
for(int k=1;k<N;k++){
double r=a[i][k];
for(int j=1;j<N;j++)
c[i][j] += r*b[k][j];
}
yang@yang-virtual-machine:~/桌面/multiply$ ./run.sh
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 419.568744 ms
优化后矩阵乘法运行耗时: 142.873895 ms
加速比为:2.936637
yang@yang-virtual-machine:~/桌面/multiply$ ./check
CHECK:
-RIGHT-
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 475.350693 ms
优化后矩阵乘法运行耗时: 144.931256 ms
加速比为:3.279836
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 471.195179 ms
优化后矩阵乘法运行耗时: 169.307161 ms
加速比为:2.783079
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 470.299077 ms
优化后矩阵乘法运行耗时: 142.539144 ms
加速比为:3.299438
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 470.839792 ms
优化后矩阵乘法运行耗时: 143.673555 ms
加速比为:3.277150
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 464.539892 ms
优化后矩阵乘法运行耗时: 144.248768 ms
加速比为:3.220408
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 467.344651 ms
优化后矩阵乘法运行耗时: 194.237274 ms
加速比为:2.406050
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 471.485065 ms
优化后矩阵乘法运行耗时: 142.872113 ms
加速比为:3.300050
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 464.633326 ms
优化后矩阵乘法运行耗时: 143.794633 ms
加速比为:3.231229
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 452.560520 ms
优化后矩阵乘法运行耗时: 163.973108 ms
加速比为:2.759968
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 473.394464 ms
优化后矩阵乘法运行耗时: 144.675783 ms
加速比为:3.272106
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 466.829666 ms
优化后矩阵乘法运行耗时: 143.055872 ms
加速比为:3.263268
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 436.283745 ms
优化后矩阵乘法运行耗时: 149.984999 ms
加速比为:2.908849
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 461.173266 ms
优化后矩阵乘法运行耗时: 148.461904 ms
加速比为:3.106341
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 470.584852 ms
优化后矩阵乘法运行耗时: 143.420487 ms
加速比为:3.281155
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 470.859915 ms
优化后矩阵乘法运行耗时: 143.617264 ms
加速比为:3.278575
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 441.426028 ms
优化后矩阵乘法运行耗时: 221.671424 ms
加速比为:1.991353
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 471.820829 ms
优化后矩阵乘法运行耗时: 143.121279 ms
加速比为:3.296650
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 472.508484 ms
优化后矩阵乘法运行耗时: 165.145991 ms
加速比为:2.861156
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 452.870419 ms
优化后矩阵乘法运行耗时: 142.621640 ms
加速比为:3.175328
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 418.838389 ms
优化后矩阵乘法运行耗时: 145.792686 ms
加速比为:2.872835
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 469.951841 ms
优化后矩阵乘法运行耗时: 142.652713 ms
加速比为:3.294377
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 471.253499 ms
优化后矩阵乘法运行耗时: 145.502747 ms
加速比为:3.238795
分块,可以达到3,但不太稳定(改变bsize及dynamic的size效果不好):
int bsize=20;
int i, j, k, kk, jj;
double sum;
int en = bsize * (N/bsize);
#pragma omp parallel shared(a,b,N,en,bsize) private(i,j,k,kk,jj,sum)
for (kk = 0; kk < en; kk += bsize) {
for (jj = 0; jj < en; jj += bsize) {
#pragma omp for schedule(dynamic,4)
for (i = 0; i < N; i++) {
for (j = jj; j < jj + bsize; j++) {
sum = c[i][j];
for (k = kk; k < kk + bsize; k++) {
sum += a[i][k]*b[k][j];
}
c[i][j] = sum;
}
}
}
}
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 478.490732 ms
优化后矩阵乘法运行耗时: 160.485123 ms
加速比为:2.981527
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 473.845689 ms
优化后矩阵乘法运行耗时: 197.628966 ms
加速比为:2.397653
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 472.802191 ms
优化后矩阵乘法运行耗时: 147.701017 ms
加速比为:3.201076
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 476.721597 ms
优化后矩阵乘法运行耗时: 149.472955 ms
加速比为:3.189350
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 267.305468 ms
优化后矩阵乘法运行耗时: 191.290913 ms
加速比为:1.397377
yang@yang-virtual-machine:~/桌面/multiply$ ./multiply
初始矩阵乘法运行耗时: 472.412870 ms
优化后矩阵乘法运行耗时: 162.142325 ms
加速比为:2.913569
2.稀疏矩阵向量乘
背景介绍: https://xupsh.github.io/pp4fpgas-cn/06-Sparse-Matrix-Vector-Multiplication.html
采用CSR存储格式: https://zhuanlan.zhihu.com/p/342942385
inline void smmSerial(const int numRows,const int *rowIndex,const int *columnIndex,const float *val,const float *x,float *r){
int rowStart;
int rowEnd;
#pragma omp parallel for schedule(dynamic)
for(int i=0;i<numRows;i++){
rowStart=rowIndex[i];
rowEnd=rowIndex[i+1];
float sum=0.0f;
for(int j=rowStart;j<rowEnd;j++){
sum+=val[j]*x[columnIndex[j]];
}
r[i]=sum;
}
}
题中的size应6
yang@yang-virtual-machine:~/桌面/openmp$ ./xsjz r[0]=0.000000,r[1]=0.000000,r[2]=0.000000,r[3]=0.000000 r[0]=160.000000,r[1]=270.000000,r[2]=520.000000,r[3]=80.000000 size=5 运行50000次耗时: 44.921875 ms r[0]=160.000000,r[1]=270.000000,r[2]=520.000000,r[3]=80.000000 size=6 运行50000次耗时: 41.015625 ms r[0]=160.000000,r[1]=270.000000,r[2]=520.000000,r[3]=80.000000 size=3 运行50000次耗时: 54.687500 ms r[0]=160.000000,r[1]=270.000000,r[2]=520.000000,r[3]=80.000000 size=4 运行50000次耗时: 48.828125 ms
测试代码:
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<stdio.h>
#include<omp.h>
using namespace std;
inline void smmSerial(const int numRows,const int *rowIndex,const int *columnIndex,const float *val,const float *x,float *r){
int rowStart;
int rowEnd;
for(int i=0;i<numRows;i++){
rowStart=rowIndex[i];
rowEnd=rowIndex[i+1];
float sum=0.0f;
for(int j=rowStart;j<rowEnd;j++){
sum+=val[j]*x[columnIndex[j]];
}
r[i]=sum;
}
}
inline void smmSerial1(const int numRows,const int *rowIndex,const int *columnIndex,const float *val,const float *x,float *r){
int rowStart;
int rowEnd;
#pragma omp parallel for schedule(dynamic,1)
for(int i=0;i<numRows;i++){
rowStart=rowIndex[i];
rowEnd=rowIndex[i+1];
float sum=0.0f;
for(int j=rowStart;j<rowEnd;j++){
sum+=val[j]*x[columnIndex[j]];
}
r[i]=sum;
}
}
inline void smmSerial2(const int numRows,const int *rowIndex,const int *columnIndex,const float *val,const float *x,float *r){
int rowStart;
int rowEnd;
#pragma omp parallel for schedule(dynamic,2)
for(int i=0;i<numRows;i++){
rowStart=rowIndex[i];
rowEnd=rowIndex[i+1];
float sum=0.0f;
for(int j=rowStart;j<rowEnd;j++){
sum+=val[j]*x[columnIndex[j]];
}
r[i]=sum;
}
}
inline void smmSerial3(const int numRows,const int *rowIndex,const int *columnIndex,const float *val,const float *x,float *r){
int rowStart;
int rowEnd;
#pragma omp parallel for schedule(dynamic,4)
for(int i=0;i<numRows;i++){
rowStart=rowIndex[i];
rowEnd=rowIndex[i+1];
float sum=0.0f;
for(int j=rowStart;j<rowEnd;j++){
sum+=val[j]*x[columnIndex[j]];
}
r[i]=sum;
}
}
inline void smmSerial4(const int numRows,const int *rowIndex,const int *columnIndex,const float *val,const float *x,float *r){
int rowStart;
int rowEnd;
#pragma omp parallel for schedule(dynamic,8)
for(int i=0;i<numRows;i++){
rowStart=rowIndex[i];
rowEnd=rowIndex[i+1];
float sum=0.0f;
for(int j=rowStart;j<rowEnd;j++){
sum+=val[j]*x[columnIndex[j]];
}
r[i]=sum;
}
}
int matrix_to_csr(int n, float **M,float* &val,int* & rowIndex,int* & columnIndex){
int i,j;
int a=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(M[i][j]!=0.0)
a++;//a非零元素个数
val=new float[a];
columnIndex=new int[a];
rowIndex=new int[n+1];
int k=0;
int p=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++){
if(j==0)
rowIndex[p++]=k;
if(M[i][j]!=0.0){
val[k]=M[i][j];
columnIndex[k]=j;
k++;}
}
rowIndex[p]=a;
return a;//a非零元素个数
}
void generate_sparse_matrix(float** & m,int n,double s){//s矩阵稀疏程度
m=new float*[n];
for(int i=0;i<n;i++)
m[i]=new float[n];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
int x=rand()%100000000;
if(x>100000000*s)
m[i][j]=0;
else
m[i][j]=(x+1)/1000000.0;
}
return;
}
void print_matrix(float **m,int n){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
cout<<m[i][j]<<",";
if(j==n-1)
cout<<endl;
}
return;
}
void generate_vector(int n,float* & x){
x=new float[n];
for(int i=0;i<n;i++)
x[i]=(rand()%100000000+1)/1000000.0;
return;
}
void print_vector(int n,float* x){
for(int i=0;i<n;i++)
cout<<x[i]<<" ";
return;
}
int main(){
srand(time(0));
int n;
double s;
cout<<"输入n:";
cin>>n;
cout<<"输入矩阵稀疏程度:";
cin>>s;
float **mat=NULL;
float *x=NULL;
float *r=NULL;
float *val=NULL;
int *columnindex=NULL;
int *rowindex=NULL;
generate_sparse_matrix(mat,n,s);
/*print_matrix(mat,n);
cout<<endl;
cout<<endl;*/
generate_vector(n,x);
//print_vector(n,x);
generate_vector(n,r);
/*cout<<endl;
cout<<endl;*/
int a=matrix_to_csr(n,mat,val,rowindex,columnindex);
float t0,t1,T0;
t0 = omp_get_wtime();
for(int i=0;i<100;i++){
smmSerial(n,rowindex,columnindex,val,x,r);
}
t1 = omp_get_wtime();
//print_vector(n,r);
//cout<<endl;cout<<endl;
T0 = (t1-t0)*1000;
printf("初始运行100耗时: %f ms\n", T0);
t0 = omp_get_wtime();
for(int i=0;i<100;i++){
smmSerial1(n,rowindex,columnindex,val,x,r);
}
t1 = omp_get_wtime();
T0 = (t1-t0)*1000;
printf("size=1 运行100耗时: %f ms\n", T0);
t0 = omp_get_wtime();
for(int i=0;i<100;i++){
smmSerial2(n,rowindex,columnindex,val,x,r);
}
t1 = omp_get_wtime();
T0 = (t1-t0)*1000;
printf("size=2 运行100耗时: %f ms\n", T0);
t0 = omp_get_wtime();
for(int i=0;i<100;i++){
smmSerial3(n,rowindex,columnindex,val,x,r);
}
t1 = omp_get_wtime();
T0 = (t1-t0)*1000;
printf("size=4 运行100耗时: %f ms\n", T0);
t0 = omp_get_wtime();
for(int i=0;i<100;i++){
smmSerial4(n,rowindex,columnindex,val,x,r);
}
t1 = omp_get_wtime();
T0 = (t1-t0)*1000;
printf("size=8 运行100耗时: %f ms\n", T0);
return 0;
}
#部分结果
yang@yang-virtual-machine:~/桌面/openmp$ g++ -fopenmp csjz.cpp -o csjz
yang@yang-virtual-machine:~/桌面/openmp$ ./csjz
输入n:500
输入矩阵稀疏程度:0.3
初始运行100耗时: 29.296875 ms
size=1 运行100耗时: 19.531250 ms
size=2 运行100耗时: 23.437500 ms
size=3 运行100耗时: 21.484375 ms
size=4 运行100耗时: 15.625000 ms
yang@yang-virtual-machine:~/桌面/openmp$ ./csjz
输入n:500
输入矩阵稀疏程度:0.3
初始运行100耗时: 31.250000 ms
size=1 运行100耗时: 21.484375 ms
size=2 运行100耗时: 19.531250 ms
size=3 运行100耗时: 21.484375 ms
size=4 运行100耗时: 23.437500 ms
yang@yang-virtual-machine:~/桌面/openmp$ ./csjz
输入n:500
输入矩阵稀疏程度:0.3
初始运行100耗时: 29.296875 ms
size=1 运行100耗时: 21.484375 ms
size=2 运行100耗时: 19.531250 ms
size=3 运行100耗时: 19.531250 ms
size=4 运行100耗时: 23.437500 ms
总结:可能是随机产生的矩阵不定因素有点多或者代码有问题,无法确定size的大小。