垃圾CPU,耗我时光——Jetson Nano 初体验2
CPU与GPU性能测试1. CPU性能测试:计算圆周率
计算圆周率的前一万位(单线程)并与? # jetson nano CPU 参数 lscpu Architecture: aarch64 Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 1 Core(s) per socket: 4 Socket(s): 1 Vendor ID: ARM Model: 1 Model name: Cortex-A57 Stepping: r1p1 CPU max MHz: 1428.0000 CPU min MHz: 102.0000 BogoMIPS: 38.40 L1d cache: 32K L1i cache: 48K L2 cache: 2048K Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 # 计算圆周率的前一万位(单线程) time echo "scale = 10000; 4*a(1)" | bc -l -q 3.1415926535897... real 5m22.161s user 5m21.496s sys 0m0.020s # Intel(R) Xeon(R) Platinum 8163 CPU 参数 lscpu Architecture: x86_64 CPU op-mode(s): 32-bit,64-bit Byte Order: Little Endian CPU(s): 1 On-line CPU(s) list: 0 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 85 Model name: Intel(R) Xeon(R) Platinum 8163 CPU @ 2.50GHz Stepping: 4 CPU MHz: 2500.008 BogoMIPS: 5000.01 Hypervisor vendor: KVM Virtualization type: full L1d cache: 32K L1i cache: 32K L2 cache: 1024K L3 cache: 33792K NUMA node0 CPU(s): 0 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f avx512dq rdseed adx smap avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 # 计算圆周率的前一万位(单线程) time echo "scale = 10000; 4*a(1)" | bc -l -q 3.1415926535897... real 2m20.695s user 2m19.211s sys 0m0.047s
单核? 2. CPU与GPU对比测试
2.1 四种计算机模型GPU设计的初衷就是为了减轻CPU计算的负载,将一部分图形计算的功能设计到一块独立的处理器中,将矩阵变换、顶点计算和光照计算等操作从 CPU 中转移到 GPU中,从而一方面加速图形处理,另一方面减小了 CPU 的工作负载,让 CPU 有时间去处理其它的事情。
2.2 CPU 与 GPU 结构差异
?
CPU 与 GPU 结构差异
(1)CPU设计理念:低延时
?
CPU设计理念:低延时
(2)GPU设计理念:大吞吐量
?
GPU设计理念:大吞吐量
GPU的虽然有dram延时,却有非常多的ALU和非常多的thread. 为了平衡内存延时的问题,我们可以中充分利用多的ALU的特性达到一个非常大的吞吐量的效果。尽可能多的分配多的Threads.通常来看GPU ALU会有非常重的pipeline就是因为这样。 2.3 Nvidia GPU架构(1)硬件架构
?
Nvidia GPU硬件架构
(2)软件架构 CUDA在软件方面组成有:一个CUDA库、一个应用程序编程接口(API)及其运行库(Runtime)、两个较高级别的通用数学库,即
?
Nvidia GPU软件架构
(3)软硬件架构对应关系 当一个kernel启动后,thread会被分配到这些SM中执行。大量的thread可能会被分配到不同的SM,同一个block中的threads必然在同一个SM中并行(SIMT)执行。每个thread拥有它自己的程序计数器和状态寄存器,并且用该线程自己的数据执行指令,这就是所谓的Single Instruction Multiple Thread。 CUDA是一种典型的 2.4 CUDA C编程入门(1)程序架构 CUDA程序构架分为两部分:Host和Device。一般而言,Host指的是CPU,Device指的是GPU。在CUDA程序构架中,主程序还是由 CPU 来执行,而当遇到数据并行处理的部分,CUDA 就会将程序编译成 GPU 能执行的程序,并传送到GPU。而这个程序在CUDA里称做核(kernel)。CUDA允许程序员定义称为核的C语言函数,从而扩展了 C 语言,在调用此类函数时,它将由N个不同的CUDA线程并行执行N次,这与普通的C语言函数只执行一次的方式不同。执行核的每个线程都会被分配一个独特的线程ID,可通过内置的threadIdx变量在内核中访问此ID。 CUDA 设备拥有多个独立的存储空间,其中包括:全局存储器、本地存储器、共享存储器、常量存储器、纹理存储器和寄存器 CUDA线程可在执行过程中访问多个存储器空间的数据,如下图所示其中:
CUDA 假设线程可在物理上独立的设备上执行,此类设备作为运行C语言程序的主机的协处理器操作。内核在GPU上执行,而C语言程序的其他部分在CPU上执行(即串行代码在主机上执行,而并行代码在设备上执行)。此外,CUDA还假设主机和设备均维护自己的DRAM,分别称为主机存储器和设备存储器。因而,一个程序通过调用CUDA运行库来管理对内核可见的全局、固定和纹理存储器空间。这种管理包括设备存储器的分配和取消分配,还包括主机和设备存储器之间的数据传输。 (2)CUDA C基础 CUDA C是对C/C++语言进行拓展后形成的变种,兼容C/C++语法,文件类型为".cu"文件,编译器为"nvcc",相比传统的C/C++,主要添加了以下几个方面:
2.5 CPU与GPU的矩阵乘法对比(1)CPU单线程矩阵乘法 // CPU单线程矩阵乘法 #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <unistd.h> #define w 2000 struct Matrix { int width; int height; float *elements; }; void matMul(float * M,float * N,float * P,int width){ for (int i = 0; i < width; i++){ for (int j = 0; j < width; j++){ float sum = 0; for (int k = 0; k < width; k++){ float a = M[i * width + k]; float b = N[k * width + j]; sum += a * b; } P[i * width + j] = sum; } } } int main(){ int width = w; int height = w; float * m = (float *)malloc (width * height * sizeof (float)); float * n = (float *)malloc (width * height * sizeof (float)); float * p = (float *)malloc (width * height * sizeof (float)); for (int i = 0; i < width * height; i++){ m[i] = 9.9; n[i] = 2.5; } struct timeval t1,t2; gettimeofday(&t1,NULL); double timeuse; matMul(m,n,p,w); gettimeofday(&t2,NULL); timeuse = t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec)/1000000.0; printf("Use Time:%fn",timeuse); return 0; }
然后编译运行 gcc cpu_sigle.c -O3 -o cpu_sigle
./cpu_sigle
Use Time:52.641901
(2)CPU多线程矩阵乘法 //CPU多线程矩阵乘法 #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define LOG_ #define SIZE 8000 int * A,* B; // 计算矩阵 int * result,* result2,* result3,* result4; // 结果矩阵 /* int A[SIZE][SIZE]; int B[SIZE][SIZE]; int result[SIZE][SIZE]; int result2[SIZE][SIZE]; int result3[SIZE][SIZE]; int result4[SIZE][SIZE]; */ int size; // 矩阵阶数 pthread_t tid2[2]; // 双线程id pthread_t tid3[3]; // 三线程id pthread_t tid4[4]; // 四线程id /* 双线程函数 */ void twoThread1(){ int i,j,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 2 == 0) result2[i * size + j] += A[i * size + k] * B[k * size + j]; // result2[i][j] += A[i][k] * B[k][j]; } } void twoThread2(){ int i,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 2 != 0) result2[i * size + j] += A[i * size + k] * B[k * size + j]; // result2[i][j] += A[i][k] * B[k][j]; } } /* 双线程函数 end */ /* 三线程函数 */ void threeThread1(){ int i,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 3 == 0) result3[i * size + j] += A[i * size + k] * B[k * size + j]; // result3[i][j] += A[i][k] * B[k][j]; } } void threeThread2(){ int i,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 3 != 0 && i % 2 != 0) result3[i * size + j] += A[i * size + k] * B[k * size + j]; // result3[i][j] += A[i][k] * B[k][j]; } } void threeThread3(){ int i,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 3 != 0 && i % 2 == 0) result3[i * size + j] += A[i * size + k] * B[k * size + j]; // result3[i][j] += A[i][k] * B[k][j]; } } /* 三线程函数 end */ /* 四线程函数 */ void fourThread1(){ int i,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 2 == 0 && i % 4 != 0) result4[i * size + j] += A[i * size + k] * B[k * size + j]; // result4[i][j] += A[i][k] * B[k][j]; } } void fourThread2(){ int i,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 4 == 0) result4[i * size + j] += A[i * size + k] * B[k * size + j]; // result4[i][j] += A[i][k] * B[k][j]; } } void fourThread3(){ int i,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 2 != 0 && i % 3 == 0) result4[i * size + j] += A[i * size + k] * B[k * size + j]; // result4[i][j] += A[i][k] * B[k][j]; } } void fourThread4(){ int i,k; for (i = 0; i < size; i++) for (j = 0; j < size; j++) for (k = 0; k < size; k++){ if (i % 2 != 0 && i % 3 != 0) result4[i * size + j] += A[i * size + k] * B[k * size + j]; // result4[i][j] += A[i][k] * B[k][j]; } } /* 四线程函数 end */ int main(){ int i,k,m,n; // 循环变量 struct timeval t1,t2; double timeuse; // 计时 char sizeChars[8]; // 阶数写入字符串 char timeChars[16]; // 耗时写入字符串 // 申请空间,计算矩阵和结果矩阵 A = (int *)malloc (sizeof (int) * SIZE * SIZE); B = (int *)malloc (sizeof (int) * SIZE * SIZE); result = (int *)malloc (sizeof (int) * SIZE * SIZE); result2 = (int *)malloc (sizeof (int) * SIZE * SIZE); result3 = (int *)malloc (sizeof (int) * SIZE * SIZE); result4 = (int *)malloc (sizeof (int) * SIZE * SIZE); for (i = 0; i < SIZE; i++) for (j = |