日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言 使用数组索引与指针索引 在循环中对编译器优化的影响及耗时分析

發布時間:2024/3/12 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言 使用数组索引与指针索引 在循环中对编译器优化的影响及耗时分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

C語言在訪問數組時既可以使用如a[i]這樣的下標方式,也可以使用*(a+i)這樣的指針方式,理論上完全等價。但是在編譯器對循環作優化時,對于指針方式的索引很有可能分析不徹底,因此相比數組索引耗時有所增加

數組索引耗時

#include <stdio.h> #include <stdlib.h> #include <time.h>unsigned long get_start_ms() {struct timespec ts;clock_gettime(CLOCK_MONOTONIC, &ts);return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); }int main() {unsigned long t = get_start_ms();uint64_t* mem = malloc(1024*1024*128*sizeof(uint64_t));register uint64_t sum = 0;for(int i = 0; i < 1024*1024*128; i++) sum += mem[i];printf("[%lums]0x%016llx\n", get_start_ms()-t, sum); }

分別編譯、運行后結果如下所示

可見隨著優化等級提升,用時依次減少。

指針索引耗時

#include <stdio.h> #include <stdlib.h> #include <time.h>unsigned long get_start_ms() {struct timespec ts;clock_gettime(CLOCK_MONOTONIC, &ts);return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); }int main() {unsigned long t = get_start_ms();uint64_t* mem = malloc(1024*1024*128*sizeof(uint64_t));uint64_t* end = mem + 1024*1024*128;register uint64_t sum = 0;while(mem<end) sum += *mem++;printf("[%lums]0x%016llx\n", get_start_ms()-t, sum); }

分別編譯、運行后結果如下所示

同樣,隨著優化等級提升,用時依次減少。但是我們注意到,在-O1時指針與數組用時大體相同,但是之后兩級都是數組比指針快約10ms,不是一個小數目。

編譯器優化分析

對于出現這種現象的原因,我們需要從匯編代碼作分析。

1. 優化等級-O1

在這一級,二者區別不明顯。

  • 數組索引
  • 指針索引

2. 優化等級-O2

在這一級,引入了向量化,但是數組索引的向量化程度更高,指令條數也更少。

  • 數組索引
  • 指針索引
cmpq $4, %r9jae LBB1_2 ## %bb.1:## implicit-def: $rbxjmp LBB1_11 LBB1_2:movq %r9, %r8andq $-4, %r8leaq -4(%r8), %rdimovq %rdi, %rsishrq $2, %rsiincq %rsimovl %esi, %ebxandl $3, %ebxcmpq $12, %rdijae LBB1_4 ## %bb.3:pxor %xmm0, %xmm0xorl %edi, %edipxor %xmm1, %xmm1testq %rbx, %rbxjne LBB1_7jmp LBB1_9 LBB1_4:movl $1, %edisubq %rsi, %rdileaq -1(%rbx,%rdi), %rsipxor %xmm0, %xmm0xorl %edi, %edipxor %xmm1, %xmm1.p2align 4, 0x90 LBB1_5: ## =>This Inner Loop Header: Depth=1movdqu 8(%rax,%rdi,8), %xmm2paddq %xmm0, %xmm2movdqu 24(%rax,%rdi,8), %xmm0paddq %xmm1, %xmm0movdqu 40(%rax,%rdi,8), %xmm1movdqu 56(%rax,%rdi,8), %xmm3movdqu 72(%rax,%rdi,8), %xmm4paddq %xmm1, %xmm4paddq %xmm2, %xmm4movdqu 88(%rax,%rdi,8), %xmm2paddq %xmm3, %xmm2paddq %xmm0, %xmm2movdqu 104(%rax,%rdi,8), %xmm0paddq %xmm4, %xmm0movdqu 120(%rax,%rdi,8), %xmm1paddq %xmm2, %xmm1addq $16, %rdiaddq $4, %rsijne LBB1_5 ## %bb.6:testq %rbx, %rbxje LBB1_9 LBB1_7:leaq 24(%rax,%rdi,8), %raxnegq %rbx.p2align 4, 0x90 LBB1_8: ## =>This Inner Loop Header: Depth=1movdqu -16(%rax), %xmm2paddq %xmm2, %xmm0movdqu (%rax), %xmm2paddq %xmm2, %xmm1addq $32, %raxincq %rbxjne LBB1_8 LBB1_9:paddq %xmm1, %xmm0pshufd $78, %xmm0, %xmm1 ## xmm1 = xmm0[2,3,0,1]paddq %xmm0, %xmm1movq %xmm1, %rbxcmpq %r8, %r9je LBB1_12 ## %bb.10:leaq (%rdx,%r8,8), %rdx.p2align 4, 0x90 LBB1_11: ## =>This Inner Loop Header: Depth=1addq (%rdx), %rbxaddq $8, %rdxcmpq %rcx, %rdxjb LBB1_11 LBB1_12:

3. 優化等級-O2 -march=native

在這一級引入了avx512,仍然是數組索引的向量化程度更高,指令條數更少。

  • 數組索引
  • 指針索引
cmpq $16, %r9jae LBB1_2 ## %bb.1:## implicit-def: $rbxjmp LBB1_11 LBB1_2:movq %r9, %r8andq $-16, %r8leaq -16(%r8), %rdimovq %rdi, %rsishrq $4, %rsiaddq $1, %rsimovl %esi, %ebxandl $3, %ebxcmpq $48, %rdijae LBB1_4 ## %bb.3:vpxor %xmm0, %xmm0, %xmm0xorl %edi, %edivpxor %xmm1, %xmm1, %xmm1vpxor %xmm2, %xmm2, %xmm2vpxor %xmm3, %xmm3, %xmm3testq %rbx, %rbxjne LBB1_7jmp LBB1_9 LBB1_4:movl $1, %edisubq %rsi, %rdileaq (%rbx,%rdi), %rsiaddq $-1, %rsivpxor %xmm0, %xmm0, %xmm0xorl %edi, %edivpxor %xmm1, %xmm1, %xmm1vpxor %xmm2, %xmm2, %xmm2vpxor %xmm3, %xmm3, %xmm3.p2align 4, 0x90 LBB1_5: ## =>This Inner Loop Header: Depth=1vpaddq 8(%rax,%rdi,8), %ymm0, %ymm0vpaddq 40(%rax,%rdi,8), %ymm1, %ymm1vpaddq 72(%rax,%rdi,8), %ymm2, %ymm2vpaddq 104(%rax,%rdi,8), %ymm3, %ymm3vpaddq 136(%rax,%rdi,8), %ymm0, %ymm0vpaddq 168(%rax,%rdi,8), %ymm1, %ymm1vpaddq 200(%rax,%rdi,8), %ymm2, %ymm2vpaddq 232(%rax,%rdi,8), %ymm3, %ymm3vpaddq 264(%rax,%rdi,8), %ymm0, %ymm0vpaddq 296(%rax,%rdi,8), %ymm1, %ymm1vpaddq 328(%rax,%rdi,8), %ymm2, %ymm2vpaddq 360(%rax,%rdi,8), %ymm3, %ymm3vpaddq 392(%rax,%rdi,8), %ymm0, %ymm0vpaddq 424(%rax,%rdi,8), %ymm1, %ymm1vpaddq 456(%rax,%rdi,8), %ymm2, %ymm2vpaddq 488(%rax,%rdi,8), %ymm3, %ymm3addq $64, %rdiaddq $4, %rsijne LBB1_5 ## %bb.6:testq %rbx, %rbxje LBB1_9 LBB1_7:leaq (%rax,%rdi,8), %raxaddq $104, %raxnegq %rbx.p2align 4, 0x90 LBB1_8: ## =>This Inner Loop Header: Depth=1vpaddq -96(%rax), %ymm0, %ymm0vpaddq -64(%rax), %ymm1, %ymm1vpaddq -32(%rax), %ymm2, %ymm2vpaddq (%rax), %ymm3, %ymm3subq $-128, %raxincq %rbxjne LBB1_8 LBB1_9:vpaddq %ymm3, %ymm1, %ymm1vpaddq %ymm2, %ymm0, %ymm0vpaddq %ymm1, %ymm0, %ymm0vextracti128 $1, %ymm0, %xmm1vpaddq %ymm1, %ymm0, %ymm0vpshufd $78, %xmm0, %xmm1 ## xmm1 = xmm0[2,3,0,1]vpaddq %xmm1, %xmm0, %xmm0vmovq %xmm0, %rbxcmpq %r8, %r9je LBB1_12 ## %bb.10:leaq (%rdx,%r8,8), %rdx.p2align 4, 0x90 LBB1_11: ## =>This Inner Loop Header: Depth=1addq (%rdx), %rbxaddq $8, %rdxcmpq %rcx, %rdxjb LBB1_11 LBB1_12:

由此可見,編譯器對for循環下的數組索引的向量化有一套成熟的優化手段,貿然改用指針索引反而會拖慢速度,一定要慎之又慎

總結

以上是生活随笔為你收集整理的C语言 使用数组索引与指针索引 在循环中对编译器优化的影响及耗时分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。