百科问答小站 logo
百科问答小站 font logo



相比其他语言,C、C++究竟快在哪里? 第1页

  

user avatar   yaobrother 网友的相关建议: 
      

请看《深入浅出DPDK》

这里举例一些书中提到的优化技术:

内存对齐:CPU cache 是以 cache line 为单位的。一次读取一个cache line的数据进入缓存。当多个CPU内核同时访问一个cache line中的数据时会产生伪共享(False Sharing),产生性能损失。C++中声明对齐变量可以使用 alignas(n) ,即以n字节对齐。并行编程中尽量避免同时访问一个cache line中的资源。

SIMD:Single-Instruction Multiple-Data(单指令多数据)的缩写,一个指令执行多个操作。在C++中 可以使用intrinsics 也可以使用编译器的自动向量化 ,OpenMP 的pragma omp simd提示 gcc和clang编译器都支持。

这是一段测试代码:

       #include <iostream> using namespace std;  alignas(32) int aa[64]; alignas(32) int bb[64]; alignas(32) int cc[64];  #pragma omp declare simd aligned(a,b:32) void add(const int*__restrict__  a,const int*__restrict__  b,int*__restrict__  c,int n) {  #pragma omp simd aligned(a,b:32)  for(int i=0;i<n;i++)  {   c[i]=a[i]+b[i];  } }  int main(int argc,char* argv[]) {  int count;  cin>>count;  for(int i=0;i<64;i++)  {   aa[i]=i+1;   bb[i]=i+count;  }  add(aa,bb,cc,64);   for(int i=0;i<64;i++)  {   cout<<cc[i];  }    return 0; }      

使用clang编译输出汇编文件:

       clang -O3 -S -o testomp.S -march=core-avx2 -fopenmp testomp.cpp     

main函数的汇编如下:

       main:                                   # @main .seh_proc main # %bb.0:  pushq %rsi  .seh_pushreg 6  pushq %rdi  .seh_pushreg 7  pushq %rbx  .seh_pushreg 3  subq $48, %rsp  .seh_stackalloc 48  .seh_endprologue  leaq "?cin@std@@3V?$basic_istream@DU?$char_traits@D@std@@@1@A"(%rip), %rcx  leaq 44(%rsp), %rdx  callq "??5?$basic_istream@DU?$char_traits@D@std@@@std@@QEAAAEAV01@AEAH@Z"  vpbroadcastd 44(%rsp), %ymm0  vmovaps __ymm@0000000800000007000000060000000500000004000000030000000200000001(%rip), %ymm1 # ymm1 = [1,2,3,4,5,6,7,8]  vmovaps %ymm1, "?aa@@3PAHA"(%rip)  vpaddd __ymm@0000000700000006000000050000000400000003000000020000000100000000(%rip), %ymm0, %ymm1  vmovdqa %ymm1, "?bb@@3PAHA"(%rip)  vmovaps __ymm@000000100000000f0000000e0000000d0000000c0000000b0000000a00000009(%rip), %ymm1 # ymm1 = [9,10,11,12,13,14,15,16]  vmovaps %ymm1, "?aa@@3PAHA"+32(%rip)  vpaddd __ymm@0000000f0000000e0000000d0000000c0000000b0000000a0000000900000008(%rip), %ymm0, %ymm1  vmovdqa %ymm1, "?bb@@3PAHA"+32(%rip)  vmovaps __ymm@0000001800000017000000160000001500000014000000130000001200000011(%rip), %ymm1 # ymm1 = [17,18,19,20,21,22,23,24]  vmovaps %ymm1, "?aa@@3PAHA"+64(%rip)  vpaddd __ymm@0000001700000016000000150000001400000013000000120000001100000010(%rip), %ymm0, %ymm1  vmovdqa %ymm1, "?bb@@3PAHA"+64(%rip)  vmovaps __ymm@000000200000001f0000001e0000001d0000001c0000001b0000001a00000019(%rip), %ymm2 # ymm2 = [25,26,27,28,29,30,31,32]  vmovaps %ymm2, "?aa@@3PAHA"+96(%rip)  vpaddd __ymm@0000001f0000001e0000001d0000001c0000001b0000001a0000001900000018(%rip), %ymm0, %ymm2  vmovdqa %ymm2, "?bb@@3PAHA"+96(%rip)  vmovaps __ymm@0000002800000027000000260000002500000024000000230000002200000021(%rip), %ymm2 # ymm2 = [33,34,35,36,37,38,39,40]  vmovaps %ymm2, "?aa@@3PAHA"+128(%rip)  vpaddd __ymm@0000002700000026000000250000002400000023000000220000002100000020(%rip), %ymm0, %ymm2  vmovdqa %ymm2, "?bb@@3PAHA"+128(%rip)  vmovaps __ymm@000000300000002f0000002e0000002d0000002c0000002b0000002a00000029(%rip), %ymm2 # ymm2 = [41,42,43,44,45,46,47,48]  vmovaps %ymm2, "?aa@@3PAHA"+160(%rip)  vpaddd __ymm@0000002f0000002e0000002d0000002c0000002b0000002a0000002900000028(%rip), %ymm0, %ymm2  vmovdqa %ymm2, "?bb@@3PAHA"+160(%rip)  vmovaps __ymm@0000003800000037000000360000003500000034000000330000003200000031(%rip), %ymm2 # ymm2 = [49,50,51,52,53,54,55,56]  vmovaps %ymm2, "?aa@@3PAHA"+192(%rip)  vpaddd __ymm@0000003700000036000000350000003400000033000000320000003100000030(%rip), %ymm0, %ymm2  vmovdqa %ymm2, "?bb@@3PAHA"+192(%rip)  vmovaps __ymm@000000400000003f0000003e0000003d0000003c0000003b0000003a00000039(%rip), %ymm2 # ymm2 = [57,58,59,60,61,62,63,64]  vmovaps %ymm2, "?aa@@3PAHA"+224(%rip)  vpaddd __ymm@0000003f0000003e0000003d0000003c0000003b0000003a0000003900000038(%rip), %ymm0, %ymm2  vmovdqa %ymm2, "?bb@@3PAHA"+224(%rip)  vpaddd __ymm@0000000f0000000d0000000b0000000900000007000000050000000300000001(%rip), %ymm0, %ymm2  vmovdqa %ymm2, "?cc@@3PAHA"(%rip)  vpaddd __ymm@0000001f0000001d0000001b0000001900000017000000150000001300000011(%rip), %ymm0, %ymm0  vmovdqa %ymm0, "?cc@@3PAHA"+32(%rip)  vpaddd "?aa@@3PAHA"+64(%rip), %ymm1, %ymm0  vmovdqa %ymm0, "?cc@@3PAHA"+64(%rip)  vmovdqa "?bb@@3PAHA"+96(%rip), %ymm0  vpaddd "?aa@@3PAHA"+96(%rip), %ymm0, %ymm0  vmovdqa %ymm0, "?cc@@3PAHA"+96(%rip)  vmovdqa "?bb@@3PAHA"+128(%rip), %ymm0  vpaddd "?aa@@3PAHA"+128(%rip), %ymm0, %ymm0  vmovdqa %ymm0, "?cc@@3PAHA"+128(%rip)  vmovdqa "?bb@@3PAHA"+160(%rip), %ymm0  vpaddd "?aa@@3PAHA"+160(%rip), %ymm0, %ymm0  vmovdqa %ymm0, "?cc@@3PAHA"+160(%rip)  vmovdqa "?bb@@3PAHA"+192(%rip), %ymm0  vpaddd "?aa@@3PAHA"+192(%rip), %ymm0, %ymm0  vmovdqa %ymm0, "?cc@@3PAHA"+192(%rip)  vmovdqa "?bb@@3PAHA"+224(%rip), %ymm0  vpaddd "?aa@@3PAHA"+224(%rip), %ymm0, %ymm0  vmovdqa %ymm0, "?cc@@3PAHA"+224(%rip)  xorl %edi, %edi  leaq "?cc@@3PAHA"(%rip), %rbx  leaq "?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A"(%rip), %rsi  .p2align 4, 0x90     

看到了吧,循环成功的进行了向量化,优化成了AVX2指令。

NUMA:(Non-UniformMemory Architecture,非一致性内存架构), 分配内存尽可能指定在本地内存上分配。使用POSIX函数pthread_setaffinity_np设定CPU的亲和性,将线程绑定到CPU内核上,避免来回切换不同内核(可能会切换到另一个CPU上)以造成性能损失。

大页内存:一般情况下x86架构CPU使用4k内存页,不过使用一些方法可以分配2M,1G的内存页。Linux系统可以使用mount hugetlbfs 或者 MMAP加上MAP_HUGETLB参数。windows系统virtualalloc加上MEMLARGEPAGES参数。使用大页内存可以减少需要的内存页表,降低tlb miss概率,从而提升性能。例如 1G内存,x86_64架构下, 4k页表会用掉2097152字节,2M页表会用掉4096字节,而1G页表只需8字节。


user avatar   zhang-hao-72 网友的相关建议: 
      

c快在基本可以知道相应的汇编是怎么写的。




  

相关话题

  c#多播或event监听太多后gc和时间都会爆炸,那么比起List<Action>存在的意义是什么? 
  什么时候用C而不用C++? 
  如何用 C++ 从零编写 GUI? 
  如何以最小的改动尽量不改变已有代码的情况下适应不断变更的需求? 
  在校学生深入学习QT后会不会找不到比较好的工作? 
  C++怎样读取文件才有最快的速度? 
  你有过哪些被 C++ 摧残的经历? 
  面向对象程序设计比传统的面向过程程序设计更有什么好处? 
  memcpy比循环赋值快吗?为什么? 
  C语言能判断一个变量是int还是float吗? 

前一个讨论
有哪些在创意跟惊悚程度上比较高级的恐怖片?
下一个讨论
以GDI,WPF,win32,Qt,DX,Unity,.net为例的几组“名词”有什么联系?





© 2024-11-21 - tinynew.org. All Rights Reserved.
© 2024-11-21 - tinynew.org. 保留所有权利