bc
命令是任意精度計算器語言,一般在 linux
下當計算器用。它相似基本的計算器, 使用這個計算器能夠作基本的數學運算man
一下 bc
便可知道,a
是 bc 的一個內置函數,表明反正切 arctan
,因爲 tan(pi/4) = 1
,因而 4*arctan(1) = pi
javascript
計算圓周率的前一萬位(單線程)並與 Intel(R) Xeon(R) Platinum 8163
CPU 的CPU作對比php
# 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
單核 CPU
性能大概是 Intel(R) Xeon(R) Platinum 8163
的一半css
GPU設計的初衷就是爲了減輕CPU計算的負載,將一部分圖形計算的功能設計到一塊獨立的處理器中,將矩陣變換、頂點計算和光照計算等操做從 CPU 中轉移到 GPU中,從而一方面加速圖形處理,另外一方面減少了 CPU 的工做負載,讓 CPU 有時間去處理其它的事情。
在GPU上的各個處理器採起異步並行的方式對數據流進行處理,根據費林分類法(Flynn's Taxonomy),能夠將信息流(information stream)分紅指令(Instruction)和數據(Data)兩種,據此又可分紅四種計算機類型:html
(1)CPU設計理念:低延時java
(2)GPU設計理念:大吞吐量node
GPU的雖然有dram延時,卻有很是多的ALU和很是多的thread. 爲了平衡內存延時的問題,咱們能夠中充分利用多的ALU的特性達到一個很是大的吞吐量的效果。儘量多的分配多的Threads.一般來看GPU ALU會有很是重的pipeline就是由於這樣。linux
(1)硬件架構程序員
(2)軟件架構編程
CUDA在軟件方面組成有:一個CUDA庫、一個應用程序編程接口(API)及其運行庫(Runtime)、兩個較高級別的通用數學庫,即CUFFT
和CUBLAS
。CUDA改進了DRAM的讀寫靈活性,使得GPU與CPU的機制相吻合。另外一方面,CUDA 提供了片上(on-chip)共享內存,使得線程之間能夠共享數據。應用程序能夠利用共享內存來減小DRAM的數據傳送,更少的依賴DRAM的內存帶寬。vim
(3)軟硬件架構對應關係
從軟件上看,SM更像一個獨立的CPU core。SM(Streaming Multiprocessors)是GPU架構中很是重要的部分,GPU硬件的並行性就是由SM決定的。
當一個kernel啓動後,thread會被分配到這些SM中執行。大量的thread可能會被分配到不一樣的SM,同一個block中的threads必然在同一個SM中並行(SIMT)執行。每一個thread擁有它本身的程序計數器和狀態寄存器,而且用該線程本身的數據執行指令,這就是所謂的Single Instruction Multiple Thread。
CUDA是一種典型的SIMT
架構(單指令多線程架構),SIMT
和SIMD
(Single Instruction, Multiple Data)相似,SIMT應該算是SIMD的升級版,更靈活,但效率略低,SIMT是NVIDIA提出的GPU新概念。兩者都經過將一樣的指令廣播給多個執行官單元來實現並行。一個主要的不一樣就是,SIMD要求全部的vector element在一個統一的同步組裏同步的執行,而SIMT容許線程們在一個warp中獨立的執行。
(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 程序中,主程序在調用任何 GPU 內核以前,必須對核進行執行配置,即肯定線程塊數和每一個線程塊中的線程數以及共享內存大小。
CUDA 設備擁有多個獨立的存儲空間,其中包括:全局存儲器、本地存儲器、共享存儲器、常量存儲器、紋理存儲器和寄存器
CUDA線程可在執行過程當中訪問多個存儲器空間的數據,以下圖所示其中:
CUDA 假設線程可在物理上獨立的設備上執行,此類設備做爲運行C語言程序的主機的協處理器操做。內核在GPU上執行,而C語言程序的其餘部分在CPU上執行(即串行代碼在主機上執行,而並行代碼在設備上執行)。此外,CUDA還假設主機和設備均維護本身的DRAM,分別稱爲主機存儲器和設備存儲器。於是,一個程序經過調用CUDA運行庫來管理對內核可見的全局、固定和紋理存儲器空間。這種管理包括設備存儲器的分配和取消分配,還包括主機和設備存儲器之間的數據傳輸。
(2)CUDA C基礎
CUDA C是對C/C++語言進行拓展後造成的變種,兼容C/C++語法,文件類型爲".cu"文件,編譯器爲"nvcc",相比傳統的C/C++,主要添加了如下幾個方面:
(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:%f\n",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, 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]; } } /* 雙線程函數 end */ /* 三線程函數 */ void threeThread1(){ int i, j, 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, j, 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, j, 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, j, 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, j, 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, j, 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, j, 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, j, 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 = 0; j < SIZE; j++){ /* A[i][j] = 1; B[i][j] = 2; result[i][j] = 0; result2[i][j] = 0; result3[i][j] = 0; result4[i][j] = 0; */ A[i * SIZE + j] = 1; B[i * SIZE + j] =