2016-06-26 14 views
3

Ich benutze die folgenden zwei Makefile, um mein Programm zu kompilieren, um Gaußsche Unschärfe zu machen.Warum verhalten sich die gleichen Kompilierungsoptionen von gcc auf unterschiedlichen Computerarchitekturen unterschiedlich?

  1. g++ -Ofast -ffast-math -march=native -flto -fwhole-program -std=c++11 -fopenmp -o interpolateFloatImg interpolateFloatImg.cpp

  2. g++ -O3 -std=c++11 -fopenmp -o interpolateFloatImg interpolateFloatImg.cpp

Meine zwei Testumgebungen sind:

  • i7 4710HQ 4 Kerne 8 Threads
  • E5 2650

Der erste Ausgang hat jedoch 2x Geschwindigkeit auf E5, aber 0.5x Geschwindigkeit auf i7. Der zweite Ausgang verhält sich auf i7 schneller, auf E5 langsamer.

Kann jemand einige Erklärungen geben?

dies ist der Quellcode: https://github.com/makeapp007/interpolateFloatImg

Ich werde so bald wie möglich mehr Details geben.

Das Programm auf i7 wird auf 8 Threads ausgeführt werden. Ich wusste nicht, wie viele Threads dieses Programm auf E5 generieren wird.

==== ==== aktualisieren

Ich bin der Mitspieler des ursprünglichen Autors zu diesem Projekt, und hier sind die Ergebnisse.

Arch-Lenovo-Y50 ~/project/ca/3/12 (git)-[master] % perf stat -d ./interpolateFloatImg lobby.bin out.bin 255 20 
Kernel kernelSize : 255 
Standard deviation : 20 
Kernel maximum: 0.000397887 
Kernel minimum: 1.22439e-21 
Reading width 20265 height 8533 = 172921245 
Micro seconds: 211199093 
Performance counter stats for './interpolateFloatImg lobby.bin out.bin 255 20': 
1423026.281358  task-clock:u (msec)  # 6.516 CPUs utilized   
      0  context-switches:u  # 0.000 K/sec     
      0  cpu-migrations:u   # 0.000 K/sec     
     2,604  page-faults:u    # 0.002 K/sec     
4,167,572,543,807  cycles:u     # 2.929 GHz      (46.79%) 
6,713,517,640,459  instructions:u   # 1.61 insn per cycle   (59.29%) 
725,873,982,404  branches:u    # 510.092 M/sec     (57.28%) 
23,468,237,735  branch-misses:u   # 3.23% of all branches   (56.99%) 
544,480,682,764  L1-dcache-loads:u   # 382.622 M/sec     (37.00%) 
545,000,783,842  L1-dcache-load-misses:u # 100.10% of all L1-dcache hits (31.44%) 
38,696,703,292  LLC-loads:u    # 27.193 M/sec     (26.68%) 
1,204,703,652  LLC-load-misses:u   # 3.11% of all LL-cache hits  (35.70%) 
218.384387536 seconds time elapsed 

Und das sind die Ergebnisse von der Workstation:

workstation:~/mossCAP3/repos/liuyh1_liujzh/12$ perf stat -d ./interpolateFloatImg ../../../lobby.bin out.bin 255 20 
Kernel kernelSize : 255 
Standard deviation : 20 
Kernel maximum: 0.000397887 
Kernel minimum: 1.22439e-21 
Reading width 20265 height 8533 = 172921245 
Micro seconds: 133661220 
Performance counter stats for './interpolateFloatImg ../../../lobby.bin out.bin 255 20': 
2035379.528531  task-clock (msec)   # 14.485 CPUs utilized   
     7,370  context-switches   # 0.004 K/sec     
      273  cpu-migrations   # 0.000 K/sec     
     3,123  page-faults    # 0.002 K/sec     
5,272,393,071,699  cycles     # 2.590 GHz      [49.99%] 
      0  stalled-cycles-frontend # 0.00% frontend cycles idle 
      0  stalled-cycles-backend # 0.00% backend cycles idle 
7,425,570,600,025  instructions    # 1.41 insns per cycle   [62.50%] 
370,199,835,630  branches     # 181.882 M/sec     [62.50%] 
47,444,417,555  branch-misses    # 12.82% of all branches   [62.50%] 
591,137,049,749  L1-dcache-loads   # 290.431 M/sec     [62.51%] 
545,926,505,523  L1-dcache-load-misses  # 92.35% of all L1-dcache hits [62.51%] 
38,725,975,976  LLC-loads     # 19.026 M/sec     [50.00%] 
1,093,840,555  LLC-load-misses   # 2.82% of all LL-cache hits [49.99%] 
140.520016141 seconds time elapsed 

==== ==== Aktualisierung die Spezifikation des E5:

workstation:~$ cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c 
    20 Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz 
workstation:~$ dmesg | grep cache 
[ 0.041489] Dentry cache hash table entries: 4194304 (order: 13, 33554432 bytes) 
[ 0.047512] Inode-cache hash table entries: 2097152 (order: 12, 16777216 bytes) 
[ 0.050088] Mount-cache hash table entries: 65536 (order: 7, 524288 bytes) 
[ 0.050121] Mountpoint-cache hash table entries: 65536 (order: 7, 524288 bytes) 
[ 0.558666] PCI: pci_cache_line_size set to 64 bytes 
[ 0.918203] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes) 
[ 0.948808] xhci_hcd 0000:00:14.0: cache line size of 32 is not supported 
[ 1.076303] ehci-pci 0000:00:1a.0: cache line size of 32 is not supported 
[ 1.089022] ehci-pci 0000:00:1d.0: cache line size of 32 is not supported 
[ 1.549796] sd 4:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA 
[ 1.552711] sd 5:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA 
[ 1.552955] sd 6:0:0:0: [sdc] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA 
+0

makeapp, können Sie die Ergebnisse von 'perf stat./InterpolateFloatImg' und' perf stat -d./InterpolateFloatImg' beider Programme auf beiden Plattformen posten? Diese Ergebnisse haben eine echte CPU-Frequenz (Zeile "Zyklen ... GHz"). Was ist dein E5-Modell (es gab verschiedene Generationen von xeon E5-CPUs: v1, v2, v3, v4)? Niemand kann Ihre Frage ohne Quellcode und detaillierte Profilerstellungsergebnisse mit der Zerlegung des Hotspots oder ohne die Möglichkeit, den Test auf dem eigenen Rechner zu reproduzieren, beantworten (http://stackoverflow.com/help/mcve - es gibt keine Minimal, Complete und Überprüfbar Beispiel in Ihrer Frage). – osgx

+0

makeapp, danke für den Code. Was ist dein Betriebssystem? Was ist deine GCC-Version (ist das für i7 und E5 gleich)? Können Sie ein Bild für die Ausführung Ihres Codes geben? Was ist Kernelgröße und Bildgröße (args)? Was ist mit 4 Ausgaben (Programm1 auf System1, Programm1 auf System2, Programm2 auf System1, Programm2 auf System2) von 'Perf stat' und 4 von' Perf stat -d'? Sie haben omp parallel für, haben Sie versucht, die Anzahl der Threads auf den gleichen Wert zu begrenzen ('export OMP_NUM_THREADS = 4') und/oder' export OMP_PROC_BIND = true'? – osgx

+0

Für i7 ist es Arch Linux. Für E5 ist es Ubuntu 14.04. Für E5 ist die g ++ - Version 4.8.2. Für i7 ist die g ++ - Version 6.1.1. Die Kernelgröße beträgt 277 10, die Genauigkeit beträgt 0,002. Das Test-Eingangsbild ist 1000 * 1000. Details sind auf http://shtech.org/course/ca/projects/3/.Ich beschränke Thread-Nummern nicht. – makeapp

Antwort

3

Ihr Programm hat ein sehr hohes Cache-Miss-Verhältnis. Ist es gut für das Programm oder schlecht dafür?

545.000.783.842 L1-dcache-Last-misses: u # 100.10% aller L1-dcache trifft

545.926.505.523 L1-dcache-Last Unfälle # 92,35% aller L1-dcache trifft

Cache Größen kann in i7 und E5 anders sein, also ist es eine Quelle der Differenz. Andere sind - verschiedene Assembler-Code, verschiedene GCC-Versionen, verschiedene GCC-Optionen.

Sie sollten versuchen, in den Code zu schauen, Hotspot zu finden, zu analysieren, wie viele Pixel von Befehlen verarbeitet werden und wie die Reihenfolge der Verarbeitung für CPU und Speicher besser sein kann. Das Umschreiben des Hotspots (der Teil des Codes, in dem die meiste Ausführungszeit verbracht wird) ist der Schlüssel zum Lösen der Aufgabe http://shtech.org/course/ca/projects/3/.

Sie perf Profiler in record/report/annotate Modus kann der Hot-Spot (es einfacher sein, wenn Sie Projekt neu kompilieren mit -g Option hinzugefügt) zu finden:

# Profile program using cpu cycle performance counter; write profile to perf.data file 
perf record ./test test_arg1 test_arg2 
# Read perf.data file and report functions where time was spent 
# (Do not change ./test file, or recompile it after record and before report) 
perf report 
# Find the hotspot in the top functions by annotation 
# you may use Arrows and Enter to do "annotate" action from report; or: 
perf annonate -s top_function_name 
perf annonate -s top_function_name > annotate_func1.txt 

konnte ich die Geschwindigkeit erhöhen für kleine bin-Datei und 277 10 Argumente in 7-mal auf meinem Handy i5-4 * (Intel haswell) mit 2 Kernen (4 virtuelle Kerne mit HT aktiviert) und AVX2 + FMA.

Das Umschreiben einiger Loops/Loop-Nester ist erforderlich. Sie sollten verstehen, wie CPU-Cache funktioniert und was einfacher ist: häufig zu verpassen oder nicht zu verpassen. Außerdem kann gcc dumm sein und kann nicht immer Muster des Lesens der Daten erkennen; Diese Erkennung kann erforderlich sein, um mehrere Pixel parallel zu bearbeiten.

+0

Wirklich vielen Dank. Ich kannte keine Werkzeuge, um die Leistung des Programms vorher zu analysieren. Und was meinst du damit, den Hotspot zu finden? Ich bin verwirrt, wie diese Daten in den Cache passen. Außerdem verwende ich SSE, um die Leistung zu verbessern, es verbessert sich um 30% der Zeit. – makeapp

+0

sollte es sein 'perf annotate -s top_funktionsname' – makeapp

+0

makeapp, können Sie nicht einfach "verwenden" sse (welche? Es gibt sse, see2, sse3, avx, avx2, fma, avx512; einige sind breiter SIMD; check wiki https://en.wikipedia.org/wiki/X86_instruction_listings#SIMD_instructions), sollten Sie sehen, was ist der Code, wie er auf Daten zugreifen, ist es High-Performance-Zugriffstyp oder nicht. Dann sollten Sie sehen, was der Assembler ist (was der Compiler getan hat). In der x86_64-Welt gibt es NUR SSE2, die mit float/doubles in der Hardware arbeiten; aber auch SSE2 kann für Skalaroperationen ("skalar", SS-Suffix) oder für vektorisierte Operationen ("gepackt", ps-Suffix) verwendet werden. Es ist Ihre Aufgabe, Programm zu optimieren, nicht meine. – osgx

4

auf dem Compiler Basierend flags, die Sie angegeben haben, verwendet das erste Makefile das -march=native Flag, das teilweise erklärt, warum Sie unterschiedliche Leistungslücken auf den zwei CPUs mit oder ohne die Markierung beobachten.

Mit diesem Flag kann GCC Anweisungen verwenden, die für eine bestimmte CPU-Architektur spezifisch sind und die nicht unbedingt in einer anderen Architektur verfügbar sind. Es impliziert auch -mtune=native, die den kompilierten Code für die bestimmte CPU der Maschine einstellt und Befehlsfolgen bevorzugt, die auf dieser CPU schneller ausgeführt werden. Beachten Sie, dass der mit -march=native kompilierte Code überhaupt nicht funktionieren kann wenn er auf einem System mit einer anderen CPU ausgeführt wird oder wesentlich langsamer ist.

Auch wenn die Optionen identisch zu sein scheinen, werden sie im Hintergrund je nach der Maschine, die Sie kompilieren, unterschiedlich agieren. Weitere Informationen zu dieser Flagge finden Sie unter GCC documentation.

Um zu sehen, welche Optionen speziell für jede CPU aktiviert sind, können Sie den folgenden Befehl auf jedem Ihrer Maschinen laufen:

gcc -march=native -Q --help=target 

Zusätzlich verschiedene Versionen von GCC haben auch einen Einfluss auf Wie verschiedene Compiler-Flags Ihren Code optimieren werden, insbesondere das Flag -march=native, das bei älteren Versionen von GCC nicht so viele Tweaks aktiviert hat (neuere Architekturen wurden zu dieser Zeit nicht unbedingt vollständig unterstützt). Dies kann die Lücken, die Sie beobachten, weiter erklären.

+0

Pyves, benutzt eine moderne gcc-Version standardmäßig march = native? makeapp, welche gcc/g ++ Version hast du? – osgx

+1

Für E5 ist die g ++ - Version 4.8.2. Für i7 ist die g ++ Version 6.1.1 – makeapp

+0

Pyves, dort ist die Quelle; und es ist nicht gut. Ich konnte es zweifach (zweimal schneller) bei 277 10 auf cropped.bin optimieren. – osgx