Why is this cpu going a lot faster?

Viewed 159

i wrote a c program, run at Intel i5-7500(kubuntu with virtualbox run at win10) and Intel Xeon E5-26xx v4(tenxun cloud). i think Intel i5-7500 will be faster(CPU MHz:3.4GHz), but Intel Xeon E5-26xx v4(CPU MHz: 2.4GHz) is faster in fact. Can someone tell me the reason, plz?

#include <stdio.h>

int main(int argc, const char *argv[]) {
    long long s = 0, i = 0;
    for (i = 0; i < 12345678900; i++) {
        s += i;
    }
    printf("%lld\n", s);
    return 0;
}

i run it with gcc -std=c11 a.c -O2 && time ./a.out

Intel(R) Xeon(R) CPU E5-26xx v4 env:

➜  ~ gcc -v                                                                  
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.4.0-1ubuntu1~18.04.1' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)
➜  ~ 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:               79
Model name:          Intel(R) Xeon(R) CPU E5-26xx v4
Stepping:            1
CPU MHz:             2394.454
BogoMIPS:            4788.90
Hypervisor vendor:   KVM
Virtualization type: full
L1d cache:           32K
L1i cache:           32K
L2 cache:            4096K
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 lm constant_tsc rep_good nopl cpuid tsc_known_freq 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 pti bmi1 avx2 bmi2 rdseed adx xsaveopt

result is

➜  ~ gcc -std=c11 a.c -O2 && time ./a.out
2420917449941559086
./a.out  4.81s user 0.00s system 99% cpu 4.849 total

Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz env:

➜  ~ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.4.0-1ubuntu1~18.04.1' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)
➜  ~ lscpu 
Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
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
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               158
Model name:          Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz
Stepping:            9
CPU MHz:             3408.002
BogoMIPS:            6816.00
Hypervisor vendor:   KVM
Virtualization type: full
L1d cache:           32K
L1i cache:           32K
L2 cache:            256K
L3 cache:            6144K
NUMA node0 CPU(s):   0-3
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single pti fsgsbase avx2 invpcid rdseed clflushopt flush_l1d

result is

➜  ~ gcc -std=c11 a.c -O2 && time ./a.out
2420917449941559086
./a.out  7.01s user 0.00s system 99% cpu 7.019 total
2 Answers

This kind of code should run much faster on a Core i5-7500, with one clock cycle per iteration and in single-core turbo mode. At 3.8 GHz, the expected run time is about 3.25 seconds.

Unless the CPU has a glitch handling such short loops (which I doubt), it's probably the combination of Windows and Virtualbox overhead that slows it down in your case. Incorrectly configured power management could be another cause.

EDIT I found a system with a 7th generation Core i5 CPU (although a slightly different one), and on bare metal, it runs the loop at one cycle per iteration.

The main issue here is the fact that you are running on cloud and virtualization on top of the existing OS. There are multiple reasons why you are not seeing the expected results:

On cloud, you don't have control how your VM is sharing the physical resources (i.e., server-node). Cloud providers heavily utilize load-balancing and consolidation, which causes significant performance variation. If you repeat your experiment, my guess is that you'll see large variations in performance, which will skew your results significantly.

On your virtual setup, you don't really provide any details about the configuration of your VM. Running at the VM layer adds significant memory usage and latency overhead.

These experiments are not really comparable given the details you provided. Running the same code on different OSes can also introduce another level of unpredictability. Power/thermal management and scheduling strategies might differ a lot from Windows to Linux. Even within the same OS, there are many control knobs that will be enough to create erroneous measurements.

If you want to compare two different processors, here are some guidelines on how to design your experiments:

  1. Since you are trying the measure the performance impact of the processor and not any other component in your system, the only variable in your experiments should be the processor type. Meaning, use the same OS, same operating environments, same power/thermal control policies, same memory capacity and speed. This will limit the variation that might occur during your experiments.

  2. Repeat the experiments until they are statistically significant. Running a benchmark only once most likely will not give you the average behavior due to cold-start.

  3. Since performance is mostly scales with frequency, you can also think about fixing the frequency of your systems, and measure your performance/MHz. This will be a better comparison, since these are two different architectures with different power/perf tradeoffs. But also there is no problem at looking at the actual execution time as the comparison point. Choosing the comparison metric mainly depends on your end goal.

Hope this helps.

Related