2016-11-22 5 views
2

Ich habe einen Fortran-Code, den ich verwende, um einige Mengen im Zusammenhang mit der Arbeit zu berechnen, die ich mache. Der Code selbst beinhaltet mehrere verschachtelte Schleifen und erfordert sehr wenig Festplatten-E/A. Wenn der Code geändert wird, führe ich ihn gegen eine Reihe von Eingabedateien (um sicherzustellen, dass er richtig funktioniert).Serial Programm läuft langsamer mit mehreren Instanzen oder parallel

Um eine lange Geschichte kurz zu machen: das letzte Update, um die Laufzeit des Programms um etwa den Faktor vier erhöht hat, und seriell mit einer CPU dauert etwa 45 Minuten jede Eingabedatei ausgeführt wird (eine lange Zeit zu warten, nur um zu sehen, ob etwas kaputt war). Folglich möchte ich jede Eingabedatei parallel über die 4 CPUs auf dem System laufen lassen. Ich habe versucht, die Parallelität über ein Bash-Skript zu implementieren.

Die interessante Sache, die ich festgestellt habe, ist, dass, wenn nur eine Instanz des Programms auf der Maschine läuft, es dauert etwa dreieinhalb Minuten, um durch eine der Eingabedateien durchzudrehen. Wenn vier Instanzen des Programms laufen, dauert es mehr als elfeinhalb Minuten, um durch eine Eingabedatei zu gehen (was meine Gesamtlaufzeit von etwa 45 Minuten auf 36 Minuten reduziert) - eine Verbesserung, ja, aber nicht ganz, was ich hatte hoffte auf).

Ich habe versucht, die Parallelität mit gnu parallel, xargs, warten und sogar nur vier Instanzen des Programms im Hintergrund von der Kommandozeile starten. Unabhängig davon, wie die Instanzen gestartet werden, sehe ich die gleiche Verzögerung. Folglich bin ich mir ziemlich sicher, dass dies kein Artefakt des Shell-Skripts ist, sondern dass irgendetwas mit dem Programm selbst passiert.

Ich habe versucht, das Programm mit deaktivierten Debugging-Symbolen neu zu erstellen und auch statische Verknüpfungen zu verwenden. Keine von diesen hatte einen spürbaren Einfluss. Ich baue das Programm derzeit mit den folgenden Optionen:

$ gfortran -Wall -g -O3 -F Backtrace -ffpe-Trap = ungültig, Null, Überlauf, Unterlauf, Denormal -fbounds-check -finit-real = nan -finit-integer = nan -o [Programmname] {Quellen}

Jede Hilfe oder Anleitung wäre sehr willkommen!

+0

Sind Sie sicher, dass Sie GNU Parallel Shell verwenden? Wenn nicht, überprüfen Sie bitte die Beschreibungen Ihrer Tags und verwenden Sie nur die zutreffenden. Ist das Bash-Tag wirklich relevant? Irgendein Code wird wahrscheinlich notwendig sein. –

+0

Ja, ich habe versucht, GNU parallel als Lösung zu verwenden. Ich habe auch versucht, mit xargs, warten und einfach mehrere Instanzen im Hintergrund starten. –

+0

Haben Sie vier Hardwarekerne? Ist Ihre Programmspeicherbandbreite schwer? Bitte geben Sie spezifischere Informationen zu Ihrer Hardware und einem Beispielprogramm an. – IanH

Antwort

1

Auf modernen CPUs können Sie keine lineare Beschleunigung erwarten. Es gibt mehrere Gründe:

  • Hyperthreading GNU/Linux Hyper-Threading als Kern sieht obwohl es kein wirklicher Kern ist. Es ist mehr wie 30% eines Kerns.

    Gemeinsam genutzte Caches Wenn sich Ihre Kerne im selben Cache befinden und eine einzelne Instanz Ihres Programms den gesamten gemeinsam genutzten Cache verwendet, erhalten Sie mehr Cache-Fehler, wenn Sie mehr Instanzen ausführen.

  • Speicherbandbreite Ein ähnlicher Fall wie der gemeinsam genutzte Cache ist die gemeinsame Speicherbandbreite. Wenn ein einzelner Thread die volle Speicherbandbreite verwendet, kann das Ausführen mehrerer paralleler Jobs die Bandbreite blockieren. Dies kann teilweise dadurch gelöst werden, dass eine NUMA ausgeführt wird, bei der jede CPU über ein gewisses RAM verfügt, das "näher" ist als das andere RAM.

  • Turbo-Modus Viele CPUs können einen einzelnen Thread mit einer höheren Taktrate als mehrere Threads ausführen. Dies ist auf Hitze zurückzuführen.

All dies wird das gleiche Symptom aufweisen: einen einzigen Thread laufen als jeder der mehreren Threads schneller sein wird, aber der Gesamtdurchsatz der mehreren Threads werden als die einzelnen Thread größer sein.

Obwohl ich Ihren Fall muss zugeben, klingt extrem: Mit 4 Kerne würde ich zumindest eine Beschleunigung von 2 erwartet

Wie der Grund

  • Hyperthreading Nutzung identifizieren taskset um auszuwählen, auf welchen Kernen ausgeführt werden soll. Wenn Sie 2 der 4 Kerne verwenden, gibt es einen Unterschied, wenn Sie # 1 + 2 oder # 1 + 3 verwenden?

  • Turbo-Modus Verwenden Sie cpufreq-set, um eine niedrige Frequenz zu erzwingen. Ist die Geschwindigkeit jetzt gleich, wenn Sie 1 oder 2 Jobs gleichzeitig ausführen?

  • Shared-Cache nicht sicher, wie dies zu tun, aber wenn es irgendwie möglich ist, den Cache zu deaktivieren, dann 1 Job 2 Jobs zu vergleichen laufen auf dem gleichen niedrigen Frequenz sollte einen Hinweis geben.

+0

-fbounds-check lässt den Code nicht schneller laufen, und einige der anderen -Walls verlangsamen auch die Dinge. Ich weiß nicht, wie man mit Cache-Misses arbeitet, ohne die wenigen Produkte, die dafür explizit ausgelegt sind. – Holmz

+0

Die Verwendung von 'taskset' und das Erzwingen der Ausführung der vier Instanzen auf zwei CPUs führt zu einer geringfügig längeren Uhrzeit im Vergleich zu vier Instanzen auf vier CPUs (12,5 Minuten im Vergleich zu 11 Minuten). Die CPU-Zeit ist wesentlich kürzer, wenn die vier Instanzen auf zwei CPUs ausgeführt werden (6,25 Minuten im Vergleich zu 10,67 Minuten). –

+0

Können Sie 2 Jobs auf 2 Kernen ausführen, aber versuchen Sie Core # 1 + 2 und dann # 1 + 3. Ist da ein Unterschied? –

Verwandte Themen