GCC optimization flag -O2 makes code much slower that -O0

Viewed 77

Here is my code.

foo() is simple. It compares the argument to some strings one by one.

main() is a little complex. It just call foo() with different strings and time it, 3 times.

#include <string.h>
#include <time.h>
#include <stdio.h>
int foo(const char *s)
{
    int r = 0;
    if (strcmp(s, "a11111111") == 0) {
        r = 1;
    } else if (strcmp(s, "b11111111") == 0) {
        r = 2;
    } else if (strcmp(s, "c11111111") == 0) {
        r = 3;
    } else if (strcmp(s, "d11111111") == 0) {
        r = 4;
    } else if (strcmp(s, "e11111111") == 0) {
        r = 5;
    } else if (strcmp(s, "f11111111") == 0) {
        r = 6;
    } else if (strcmp(s, "g11111111") == 0) {
        r = 7;
    }
    return r;
}

int main()
{
    char *ss[] = {
        "a11111111",
        "b11111111",
        "c11111111",
        "d11111111",
        "e11111111",
        "f11111111",
        "g11111111",
        "h11111111",
    };

    int r = 0;
    for (int i = 0; i < 3; i++) {
        clock_t begin = clock();
        for (int j = 0; j < 100000; j++) {
            r = foo(ss[r]);
        }
        printf("%lu\n", clock() - begin);
    }

    return r;
}

Here is the result:

$ gcc tmp.c
$ ./a.out
3979
4025
4272
$
$ gcc tmp.c -O2
$ ./a.out
20575
14572
13841
$

As you can see, -O2 makes the code much slower. Why?

GCC version: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12)

Thanks in advance,

Wu

==== EDIT ====

Thanks @Ville Krumlinde. I make another code to test strcmp only. There are 2 files:

//// main.c
#include <time.h>
#include <stdio.h>

int x_strcmp(const char *a);

int main()
{
    int r = 0;
    for (int i = 0; i < 3; i++) {
        clock_t begin = clock();
        for (int j = 0; j < 100000; j++) {
            r += x_strcmp("a111111111");
        }
        printf("%lu\n", clock() - begin);
    }

    return r;
}
//// tmps.c
#include <string.h>
int x_strcmp(const char *a)
{
    return strcmp(a, "a11111111");
}

The result:

$ gcc main.c -O2 -c
$
$ gcc tmps.c -c && cc main.o tmps.o -o a.out
$ ./a.out
870
896
857
$
$ gcc tmps.c -c -O2 && cc main.o tmps.o -o a.out
$ ./a.out
6290
5191
6382
$

The only difference is with or without -O2 when compiling tmps.c. And the flag still makes the code much slower.

Here are the assembly code:

#without -O2
x_strcmp:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    %rdi, -8(%rbp)
        movq    -8(%rbp), %rax
        movl    $.LC0, %esi
        movq    %rax, %rdi
        call    strcmp
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
# with -O2
x_strcmp:
.LFB24:
        .cfi_startproc
        movq    %rdi, %rsi
        movl    $10, %ecx
        movl    $.LC0, %edi
        repz cmpsb
        seta    %al
        setb    %dl
        subl    %edx, %eax
        movsbl  %al, %eax
        ret
        .cfi_endproc
0 Answers
Related