const在哪里降低性能而不是优化它?

时间:2018-04-26 04:36:02

标签: c optimization const compiler-optimization

请查看以下代码段

#define HF_ND_SZ sizeof(struct huffman_node)
#define TSIZE_MAX 256

struct huffman_node * build_decomp_huffman_tree(uint64_t *table, int size) {
    static struct huffman_node huffman_node_list2[TSIZE_MAX * 3];
    int i = 0, j = 0;
    int k = TSIZE_MAX * 2; // this is the case point 1
    //...//
    for (i = 0; i < size - 1; i++) {
        huffman_node_list2[k + i] = huffman_node_list2[i + 1]; // point 2
        huffman_node_list2[TSIZE_MAX + i].right = &huffman_node_list2[k+ i];
    // ... //
    }
    return &huffman_node_list2[size - 1];
}

为简单起见,我减少了代码并指出了我想要突出显示的位置,也不认为算法和结构太深。

我想要的是,如果我们将第1点定义为const int k = TSIZE_MAX * 2;,那么是否有任何优化发生在第2点或第3点,其中分配发生在连续数据(数组)huffman_node_list2[k + i] = huffman_node_list2[i + 1];

(请注意并纠正我的假设,如果它是错误的,我认为当我们在本地或全球范围内声明const它被创建为不可变的内存分配时,如果我们使用不可变内存并在循环结构中执行数学运算,如第2点或第3点[k + i]),在运行时程序中必须< strong>加载不可变内存循环的每次迭代并将结果存储在临时内存位置,如果不可变内存有大块,如果发生,希望你能抓住我的想法,我是否正确?)

3 个答案:

答案 0 :(得分:1)

使用Visual C,我编译了代码的两个版本:使用const int k而不使用const。标志/FA在(某些)人可读的.asm文件中生成代码机。没有使用优化标志。

结果是:没有优化,没有区别。生成的机器代码严格相同:

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.00.24231.0 

    TITLE   opt_const.c
    .686P
    .XMM
    include listing.inc
    .model  flat

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

PUBLIC  _main
_BSS    SEGMENT
?huffman_node_list2@?1??main@@9@9 DB 01fd4H DUP (?) ; `main'::`2'::huffman_node_list2
_BSS    ENDS
; Function compile flags: /Odtp
; File c:\joël\tests\opt_const.c
_TEXT   SEGMENT
_j$ = -16                       ; size = 4
_size$ = -12                        ; size = 4
_k$ = -8                        ; size = 4
_i$ = -4                        ; size = 4
_argc$ = 8                      ; size = 4
_argv$ = 12                     ; size = 4
_main   PROC

; 10   : {

    push    ebp
    mov ebp, esp
    sub esp, 16                 ; 00000010H
    push    esi
    push    edi

; 11   :     static struct huffman_node huffman_node_list2[TSIZE_MAX * 3];
; 12   :     int i = 0, j = 0, size = 17;

    mov DWORD PTR _i$[ebp], 0
    mov DWORD PTR _j$[ebp], 0
    mov DWORD PTR _size$[ebp], 17       ; 00000011H

; 13   :     int k = TSIZE_MAX * 2; // this is the case point 1

    mov DWORD PTR _k$[ebp], 194         ; 000000c2H

; 14   :     //...//
; 15   :     for (i = 0; i < size - 1; i++) {

    mov DWORD PTR _i$[ebp], 0
    jmp SHORT $LN4@main
$LN2@main:
    mov eax, DWORD PTR _i$[ebp]
    add eax, 1
    mov DWORD PTR _i$[ebp], eax
$LN4@main:
    mov ecx, DWORD PTR _size$[ebp]
    sub ecx, 1
    cmp DWORD PTR _i$[ebp], ecx
    jge SHORT $LN3@main

; 16   :         huffman_node_list2[k + i] = huffman_node_list2[i + 1]; // point 2

    mov edx, DWORD PTR _i$[ebp]
    add edx, 1
    imul    esi, edx, 28
    add esi, OFFSET ?huffman_node_list2@?1??main@@9@9
    mov eax, DWORD PTR _k$[ebp]
    add eax, DWORD PTR _i$[ebp]
    imul    edi, eax, 28
    add edi, OFFSET ?huffman_node_list2@?1??main@@9@9
    mov ecx, 7
    rep movsd

; 17   :         huffman_node_list2[TSIZE_MAX + i].right = &huffman_node_list2[k+ i];

    mov ecx, DWORD PTR _k$[ebp]
    add ecx, DWORD PTR _i$[ebp]
    imul    edx, ecx, 28
    add edx, OFFSET ?huffman_node_list2@?1??main@@9@9
    mov eax, DWORD PTR _i$[ebp]
    add eax, 97                 ; 00000061H
    imul    ecx, eax, 28
    mov DWORD PTR ?huffman_node_list2@?1??main@@9@9[ecx], edx

; 18   :     // ... //
; 19   :     }

    jmp SHORT $LN2@main
$LN3@main:

; 20   :     return 0;

    xor eax, eax

; 21   : }

    pop edi
    pop esi
    mov esp, ebp
    pop ebp
    ret 0
_main   ENDP
_TEXT   ENDS
END
编辑:我使用gcc,-O3优化标志进行了相同的测试。 并且......相同的结果:生成的汇编代码在有const关键字的情况下再次严格相同。

        .file       "opt_const.c"
        .section    .text.unlikely,"ax",@progbits
.LCOLDB0:
        .section    .text.startup,"ax",@progbits
.LHOTB0:
        .p2align 4,,15
        .globl      main
        .type       main, @function
main:
.LFB23:
        .cfi_startproc
        movl        $huffman_node_list2.2488+16384, %eax
        .p2align 4,,10
        .p2align 3
.L2:
        movq        -16352(%rax), %rdx
        movq        %rax, -8192(%rax)
        addq        $32, %rax
        movq        %rdx, -32(%rax)
        movq        -16376(%rax), %rdx
        movq        %rdx, -24(%rax)
        movq        -16368(%rax), %rdx
        movq        %rdx, -16(%rax)
        movq        -16360(%rax), %rdx
        movq        %rdx, -8(%rax)
        cmpq        $huffman_node_list2.2488+17088, %rax
        jne .L2
        xorl        %eax, %eax
        ret
        .cfi_endproc
.LFE23:
        .size       main, .-main
        .section    .text.unlikely
.LCOLDE0:
        .section    .text.startup
.LHOTE0:
        .local      huffman_node_list2.2488
        .comm       huffman_node_list2.2488,24576,32
        .ident      "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609"
        .section    .note.GNU-stack,"",@progbits

答案 1 :(得分:1)

const 如果编译器将它放在只读的.text段中足够远,导致高速缓存未命中,则会慢一些。

这可能发生在全局const或者编译器将其从函数中提升而不是必须使用指令构建它(结构或数组的相当常见的优化)这可以减少代码大小,如果多个函数使用相同的常量,但也会增加与代码的距离,从而增加导致错过的可能性。

由于您没有使用任何聚合类型,因此与优秀的编译器应该没有区别。

有一篇很好的文章介绍了如何布置不同的数据here

答案 2 :(得分:0)

const根本不会创建内存位置,除非您获取其地址。它们可以作为立即模式常量消失在指令流中,或者在编译或链接时添加到地址中。

例如,huffman_node_list2[k + i] = huffman_node_list2[i + 1]几乎肯定被编译为huffman_node_list2[TSIZE_MAX * 2 + i] = huffman_node_list2[i + 1],其中不仅在编译时评估TSIZE_MAX * 2,而且在链接时评估huffman_node_list2+TSIZE_MAX*2