Prozessor richtig auslasten



  • Ich habe ein kleines Programm geschrieben, welches alle random Zahlen initialisiert und ausrechnet und dann in einer .txt speichert.
    Realisiert habe ich es so:

    #include "stdafx.h"
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) {
    		std::cout << "Priorität erhöhen fehlgeschlagen" << std::endl;
    		system("PAUSE");
    		return 0;
    	}
    	int mintime;
    	int maxtime;
    	int maxdiv;
    	std::cout << "Minimale Systemzeit" << std::endl;
    	std::cin >> mintime;
    	std::cout << "Maximale Systemzeit" << std::endl;
    	std::cin >> maxtime;
    	std::cout << "Maximale Division (keine 0)" << std::endl;
    	std::cin >> maxdiv;
    	if (maxdiv < 1)
    		return 0;
    	std::ofstream stream;
    	stream.open("random.txt", std::ios::out);
    	stream << "Minimale Systemzeit: " << mintime << "\n";
    	stream << "Maximale Systemzeit: " << maxtime << "\n";
    	stream << "Maximale Division: " << maxdiv << "\n";
    	timer time; // timer Klasse
    	time.init();
    	time.begin();
    	#pragma omp for
    	for (int i = mintime; i < maxtime; i++) {
    		for (int j = 1; j <= maxdiv; j++) {
    			srand(i);
    			stream << i << "." << j << ":\t\t" << rand() % j << "\n";
    			std::cout << i << j << std::endl;
    		}
    	}
    	double deltatime = time.stop();
    	stream << "Benötigte Zeit in Sekunden: " << deltatime << "\n";
    	stream.close();
    	std::cout << deltatime << std::endl;
    	system("PAUSE");
    	return 0;
    }
    

    Die klasse timer berechnet einfach die vergangene Zeit.
    Und jetzt habe ich auch direkt eine Nebenfrage: Wieso schafft es system("PAUSE") die Konsole offen zu halten aber getchar() nicht? getchar() wird in diesem Programm völlig ignoriert.

    Aber jetzt zur eigentlichen Frage:
    Ich wollte das Programm auch für Mehrkern-Prozessoren interessant machen und habe deswegen kurz OpenMP vor die for Schleife gesetzt. Jetzt habe ich es auf 2 Prozessoren ausporbiert und habe festgestellt, dass der 4 Kern Prozssor um einiges langsamer ist:
    Intel Pentium 4 3.06 GHz - 1.26105 Sekunden
    Intel i7 720QM 1,6 GHz - 12.2592 Sekunden
    Bei den Werten 0, 100, 100.

    Der Grund daran ist, dass der i7 Prozessor nahezu im Ruhezstand bleibt, während der Pentium Prozssor mit 100% ackert. Also habe ich es mit SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS), dass sogar verhindert, dass der Task Manager mit dem Pentium Prozessor geöffnet wird. Der i7 Prozessor bleibt jedoch weiterhin im idle Zustand.

    Wie schaffe ich es jetzt, auch den i7 Prozessor zum arbeiten zu bringen? 🤡


  • Mod

    Zu system("PAUSE"): FAQ, Eintrag 2

    Zur Systemauslastung: Um deine frage mal für spätere Leser verständlich zu machen: Du möchtest also mittels Open MP schnell parallel viele Zufallszahlen ziehen und in eine Datei schreiben?

    Allgemeine Überlegung: "Schnell" und "Parallel" passen nicht zu "in Datei schreiben". Egal wie toll dein Programm ist, das langsamste ist immer die Ausgabe. Wenn es dir nur darum geht Zufallszahlen in die Datei zu schreiben, vergiss alle Optimierung. Mach das OMP #pragma weg und lass einfach alles beim alten. Du gewinnst dadurch nichts, wirst im Zweifelsfalle aber langsamer, weil sich die Threads gegenseitig in die Quere kommen. Vermutlich ist genau das hier der Fall.

    P.S.: Ist dir eigentlich klar, was srand(i) macht? Du kannst dir das ganze rand() sparen und einfach i als "Zufallswert" nehmen, wenn du den Zufallsgenerator so wie hier benutzt. Informier dich lieber erst einmal wie etwas funktioniert, bevor du es benutzt.



  • Zu system("PAUSE"): FAQ, Eintrag 2

    ... Ich wollte wissen, wieso getchar in diesem Fall nicht wie gewohnt auf ein enter wartet sondern komplett effektlos ist.

    Zur Systemauslastung: Um deine frage mal für spätere Leser verständlich zu machen: Du möchtest also mittels Open MP schnell parallel viele Zufallszahlen ziehen und in eine Datei schreiben?

    Schnell ja, irgendwelche "Zufallszahlen" ziehen nicht. Ich möchte einfach eine Liste haben, in der ich z.B. sehe, wenn man die random Funktion mit mit 1 initialisiert und dann mit Modulo 100 teile.
    So sieht das dann nachher aus: Link

    Allgemeine Überlegung: "Schnell" und "Parallel" passen nicht zu "in Datei schreiben". Egal wie toll dein Programm ist, das langsamste ist immer die Ausgabe. Wenn es dir nur darum geht Zufallszahlen in die Datei zu schreiben, vergiss alle Optimierung. Mach das OMP #pragma weg und lass einfach alles beim alten. Du gewinnst dadurch nichts, wirst im Zweifelsfalle aber langsamer, weil sich die Threads gegenseitig in die Quere kommen. Vermutlich ist genau das hier der Fall.

    Inwiefern kommen sich die Threads in die quere? Kann immer nur ein Thread die Datei schreiben? Wenn ich für jeden Thread eine eigene Datei hätte, wäre das doch kein Problem mehr oder? Dazu hat man ja die tollen Vierkern Prozessoren mit Hyperthreading.

    P.S.: Ist dir eigentlich klar, was srand(i) macht? Du kannst dir das ganze rand() sparen und einfach i als "Zufallswert" nehmen, wenn du den Zufallsgenerator so wie hier benutzt. Informier dich lieber erst einmal wie etwas funktioniert, bevor du es benutzt.

    Siehe oben was ich vorhabe. Das aufjedenfall nicht.



  • Pikkolini schrieb:

    Inwiefern kommen sich die Threads in die quere? Kann immer nur ein Thread die Datei schreiben? Wenn ich für jeden Thread eine eigene Datei hätte, wäre das doch kein Problem mehr oder? Dazu hat man ja die tollen Vierkern Prozessoren mit Hyperthreading.

    Multithreading (Hyperthreading ist eine von Intel patentierte Technologie, mit der auf einem Prozessorkern parallel zwei Threads rechnen können) macht Festplattenzugriffe nicht schneller. Was dir SeppJ sagen wollte: Wenn du viel in eine Datei schreiben willst, wird das der Flaschenhals werden. Parallelisierung von Berechnungen wird nur bedingt (also fast gar nicht) die Gesamtlaufzeit deiner Anwendung verbessern.
    Wenn du jetzt tatsächlich vor hast, eine Datei pro Thread zu beschreiben, kannst du dir das Resultat selber denken...
    Was könntest du tun? Wenn du unbedingt parallel berechnen willst, dann schreib dir einen Puffer, der (durch einen Mutext geschützt) Aufträge entgegen nimmt. Sind alle Threads durch, schreibt der Puffer alle Daten auf einen Rutsch - evtl. sortiert, gefiltert, aufgewertet, ... - in die Datei.


  • Administrator

    Pikkolini schrieb:

    ... Ich wollte wissen, wieso getchar in diesem Fall nicht wie gewohnt auf ein enter wartet sondern komplett effektlos ist.

    Wahrscheinlich weil noch etwas im Eingabepuffer ist. Im von SeppJ verlinkten Thread und einem weiterführenden verlinkten Thread (Automatisches Schliessen verhindern), hättest du sehen können, dass die gängigen Lösungen, zuerst den Eingabepuffer leeren.

    Pikkolini schrieb:

    Inwiefern kommen sich die Threads in die quere? Kann immer nur ein Thread die Datei schreiben? Wenn ich für jeden Thread eine eigene Datei hätte, wäre das doch kein Problem mehr oder?

    Durch paralleles Schreiben wird die Festplatte nicht auf wundersame Art schneller. Du schreibst schliesslicht über EINE Schnittstelle auf die HD. Am Ende muss irgendwo synchronisiert werden.
    Zudem ist, wie schon zweimal gesagt wurde, die grösste Bremse das I/O. Die meiste Zeit wird somit in der I/O Schnittstelle verbraten. Bei deinem Code wohl ca. 99%.

    Pikkolini schrieb:

    Dazu hat man ja die tollen Vierkern Prozessoren mit Hyperthreading.

    Wie jetzt? Hyperthreading hat nichts mit Zugriff auf das Filesystem zu tun.

    Grüssli



  • Multithreading (Hyperthreading ist eine von Intel patentierte Technologie, mit der auf einem Prozessorkern parallel zwei Threads rechnen können)

    Hyperthreading habe ich schon gemeint, war ja auf den Prozessot bezogen.

    Wenn du viel in eine Datei schreiben willst, wird das der Flaschenhals werden. Parallelisierung von Berechnungen wird nur bedingt (also fast gar nicht) die Gesamtlaufzeit deiner Anwendung verbessern.

    Hmm, rein nach den Werten gesehen soll die Festplatte von dem Laptop schneller sein, muss ich aber mal ausprobieren. Aber so viel langsamer kann die ja gar nicht sein, und der Pentium 4 Prozessor arbeitet ja auch mit 100%, dass muss ja irgendeinen Grund haben.

    Was könntest du tun? Wenn du unbedingt parallel berechnen willst, dann schreib dir einen Puffer, der (durch einen Mutext geschützt) Aufträge entgegen nimmt. Sind alle Threads durch, schreibt der Puffer alle Daten auf einen Rutsch - evtl. sortiert, gefiltert, aufgewertet, ... - in die Datei.

    Das wäre eine möglichkeit, aber sehr aufwändig für so etwas simples 😉

    Wahrscheinlich weil noch etwas im Eingabepuffer ist. Im von SeppJ verlinkten Thread und einem weiterführenden verlinkten Thread (Automatisches Schliessen verhindern), hättest du sehen können, dass die gängigen Lösungen, zuerst den Eingabepuffer leeren.

    Ja das war es. Die weiterführenden Threads habe ich gerade nicht gelesen. Danke für den Hinweis

    Durch paralleles Schreiben wird die Festplatte nicht auf wundersame Art schneller. Du schreibst schliesslicht über EINE Schnittstelle auf die HD. Am Ende muss irgendwo synchronisiert werden.
    Zudem ist, wie schon zweimal gesagt wurde, die grösste Bremse das I/O. Die meiste Zeit wird somit in der I/O Schnittstelle verbraten. Bei deinem Code wohl ca. 99%.

    Das mit dem I/O und so ist mir jetzt klar. Aber wie schon gesagt ist es mir ein Rätsel wieso der Pentium 4 dann dafür so ackert und im Endeffekt damit auch schneller ist. Auch wenn alle Optimierungen von wegen Multithreading etc. entfernt sind.

    Wie jetzt? Hyperthreading hat nichts mit Zugriff auf das Filesystem zu tun.

    Den Begriff habe ich in dem Zusammenhang mit der Rechenzeit benutzt. Von Zugriff aus Filesystem etc. habe ich in meinem letzten Post ja gar nicht geradet, da kamt ihr auf die Idee 😃


  • Administrator

    Pikkolini schrieb:

    Das mit dem I/O und so ist mir jetzt klar. Aber wie schon gesagt ist es mir ein Rätsel wieso der Pentium 4 dann dafür so ackert und im Endeffekt damit auch schneller ist. Auch wenn alle Optimierungen von wegen Multithreading etc. entfernt sind.

    Darf ich fragen, ob du jeweils den gleichen Kompiler und das gleiche Betriebsystem verwendet hast?

    Pikkolini schrieb:

    Wie jetzt? Hyperthreading hat nichts mit Zugriff auf das Filesystem zu tun.

    Den Begriff habe ich in dem Zusammenhang mit der Rechenzeit benutzt. Von Zugriff aus Filesystem etc. habe ich in meinem letzten Post ja gar nicht geradet, da kamt ihr auf die Idee 😃

    Nein, du hast davon geredet, mit mehreren Threads in mehrere Dateien zu schreiben und meintest, dass doch genau dazu Hyperthreading vorhanden sei. Wenn ich dich mal zitieren darf:

    Pikkolini schrieb:

    Inwiefern kommen sich die Threads in die quere? Kann immer nur ein Thread die Datei schreiben? Wenn ich für jeden Thread eine eigene Datei hätte, wäre das doch kein Problem mehr oder? Dazu hat man ja die tollen Vierkern Prozessoren mit Hyperthreading.

    Oder was hast du mit dem "dazu" gemeint?

    Grüssli



  • Darf ich fragen, ob du jeweils den gleichen Kompiler und das gleiche Betriebsystem verwendet hast?

    Die .exe ist exakt die selbe. Der PC mit dem Pentium 4 läuft mit WinXP und der andere mit Windows 7 64 bit.

    Nein, du hast davon geredet, mit mehreren Threads in mehrere Dateien zu schreiben und meintest, dass doch genau dazu Hyperthreading vorhanden sei. Wenn ich dich mal zitieren darf:
    Pikkolini schrieb:
    Inwiefern kommen sich die Threads in die quere? Kann immer nur ein Thread die Datei schreiben? Wenn ich für jeden Thread eine eigene Datei hätte, wäre das doch kein Problem mehr oder? Dazu hat man ja die tollen Vierkern Prozessoren mit Hyperthreading.

    Oder was hast du mit dem "dazu" gemeint?

    Ok, das habe ich ein bisschen seltsam formuliert. Ich meinte eigentlich, dass Hyperthreading generell dazu da sei, mehr Threads verarbeiten zu können, ohne dass sich diese in die Quere kommen. Das es nur eine Festplattenschnittstelle gibt, habe ich jetzt auch verstanden 😃

    Dennoch stellt sich mir immernoch die Frage, wieso der vermeintlich schnellere PC um einiges langsamer ist als der vermeintlich langsamere. An dem Betriebssystem wird es wohl kaum liegen, oder doch?


  • Administrator

    Pikkolini schrieb:

    An dem Betriebssystem wird es wohl kaum liegen, oder doch?

    Das ist durchaus eine meiner Vermutungen. Allerdings werden wohl auch noch andere Komponenten abweichen. Du kannst nicht auf zwei völlig unterschiedlichen Computern Messungen durchführen und dann nur die CPU vergleichen. Es ist schon schwierig genug auf dem gleichen Computer sinnvolle Messungen zu erzielen. Das was du gemacht hast, bringt überhaupt gar nichts. Es dürfte ziemlich schwer werden, die genaue Ursache zu ermitteln.

    Grüssli



  • Hallo

    In deinem Beispiel sind die Berechnung von einander unabhängig. Für möglichst parallele Ausführung sollte während der Berechnung möglichst kein System-Call (egal ob IO oder Mutex) ausgeführt werden

    (Pseudo-)Code sagt mehr als 1000 Worte:

    //Pseudo-Code:
    void worker_proc(DataType * ptr, int begin, int end)
    {
      for(int i = begin, i < end; ++i)
      {
        ptr[i] = do_something(ptr[i]);
      }
    }
    ...
    DataType myData[10000];
    ...
    ThreadType thread1 = thread_create(&worker_proc, myData, 0, 2500);
    ThreadType thread2 = thread_create(&worker_proc, myData, 2500, 5000);
    ThreadType thread3 = thread_create(&worker_proc, myData, 5000, 7500);
    ThreadType thread4 = thread_create(&worker_proc, myData, 7500, 10000);
    thread_join(thread1);
    thread_join(thread2);
    thread_join(thread3);
    thread_join(thread4);
    ...
    fwrite(myData, sizeof(DataType), sizeof(myData) / sizeof(DataType), outputFile);
    ...
    

    Ich will OpenMP nicht grundsätzlich schlechtreden, aber ob es für jeden Algorithmus und jede Situation die beste Lösung automatisch findet, wage ich zu bezweifeln. Die Anzahl der Threads hängt von den CPUs ab, die man aber unter den meisten Systemen auch auslesen kann.

    cu

    PS: Die Implementierung der iostreams auf MSVC benutzt locks bei jedem einzelnen geschriebenen Zeichen (->unerträglicher Overhead). Ich kenne zwar die Implementierung der Mutexe unter Windows nicht, aber jeder Kernel-Call auf einer CPU kann die anderen CPUs anhalten. Durch die Verwaltung von 8 Kernen statt etwa nur 2 braucht das Umschalten im Scheduler vielleicht wirklich mehr Zeit ist daher unter Umständen langsamer ... aber es ist seeeehhhr schwer genau zu wissen was wirklich passiert ... alles nur Spekulation 😃

    Fazit: Wenn man eine IO-Operation mit einem einzigen Aufruf durchführen kann, dann immer gleich so machen und nicht jedes einzelne Byte schreiben..., und was Windows anbelangt: Jede Version ist irgend wie anders :p. Auf der 64-bit Maschine muss dein 32-bit Programm erst durch einen eigenen Kompatibilitätslayer durchrufen, bei XP geht's direkt 😉



  • Pikkolini schrieb:

    An dem Betriebssystem wird es wohl kaum liegen, oder doch?

    Was glaubst Du denn "wo" das Multithreading realisiert wird? Richtig im Betriebssystem (Kernel). Ist es daher zu erwarten das das Betriebssystem Einfluß auf das Verhalten des Multithreasding hat? Aber sowas von...



  • loks schrieb:

    Was glaubst Du denn "wo" das Multithreading realisiert wird? Richtig im Betriebssystem (Kernel). Ist es daher zu erwarten das das Betriebssystem Einfluß auf das Verhalten des Multithreasding hat? Aber sowas von...

    Ja das ist klar aber
    1. Habe ich nur ganz selten Multithreading benutzt, kann man aber auch aus meinen vorherogen Posts rauslesen
    2. Wieso sollte Microsoft Windows 7 so verkorksen, dass irgendwelche Programme deswegen nicht mehr so schnell laufen, wie z.B. auf Windows XP? Ich denke aber, dass es an dem 64-Bit System liegt.

    So ich wollte das jetzt so wie xor realisieren, und habe mir die Threads die boost Library genommen. Allerdings spuckt der Linker im den Fehler aus, dass er die Datei "libboost_thread-vc100-mt-s-1_43.lib" nicht finden kann, obwohl ich die libs richtig gelinkt habe (egal ob Debug oder Release). Das liegt aber daran, dass diese Datei nicht exisitiert sondern nur diese hier:
    libboost_thread-vc100-mt-1_43.lib
    libboost_thread-vc100-mt.lib
    libboost_thread-vc100-mt-gd-1_43.lib
    libboost_thread-vc100-mt-gd.lib

    Boost habe ich installiert, indem ich die bjam.exe einfach ausgeführt habe.
    Liegt der Fehler jetzt daran, dass boost nicht richtig installiert wurde, und ich das nochmal stundenlang neu installieren muss, oder gibt es eine andere Erklärung und Lösung dafür?



  • Ich kenne mich mit Windows überhaupt nicht aus, nehme aber an, dass das zusätzliche "s" im Namen auf "static hindeutet. Linkst du denn statisch? Hast du eine statische Version von boost-thread erstellt?



  • Ja ich linke es statisch, und dadurch, dass nur statische libs erstellt wurden und im sourcecode nichts von dynamischen libs steht, denke ich mal, dass ich auch die statische Version erstellt habe.
    Allerdings hatte ich bei der Installation in der Konsole einiger Fehler, die ich bis jetzt ignoriert hatte. Vielleicht liegt es daran. Außerdem habe ich gelesen, dass boost standardmäßig nur minimal installiert wird, damit es schneller geht. Ich versuche es jetzt mal komplett zu installieren.



  • Hmm, ich habe es jetzt so gemacht, wie ich beschrieben habe und das Problem ist das selbe. Ich habe genau die lgeichen Dateien bekommen wie vorher. Kann jemand mal bitte erklären, wie er die boost lib installiert hat? Wäre echt nett und vielleicht sehe ich dann, was noch gefehlt / nicht gestimmt hat.



  • loks schrieb:

    Pikkolini schrieb:

    An dem Betriebssystem wird es wohl kaum liegen, oder doch?

    Was glaubst Du denn "wo" das Multithreading realisiert wird? Richtig im Betriebssystem (Kernel). Ist es daher zu erwarten das das Betriebssystem Einfluß auf das Verhalten des Multithreasding hat? Aber sowas von...

    Wie wärs mal mit Fakten?



  • So, ich habe jetzt nochmal ein paar Parameter bei der Installation geändert und jetzt habe ich auch die statischen Libs. Andere Alternative wäre natürlich gewesen, die einfach dynamisch zu linken.



  • Ich habe nochmal 2 Fragen :p

    1. Nachdem ich Boost eingebunden habe, spuckt der Debugger immer das hier aus:

    Eine Ausnahme (erste Chance) bei 0x7c812afb in Random.exe: Microsoft C++-Ausnahme: boost::exception_detail::clone_impl<boost::exception_detail::bad_alloc_> an Speicherposition 0x0012feec..
    Eine Ausnahme (erste Chance) bei 0x7c812afb in Random.exe: Microsoft C++-Ausnahme: [rethrow] an Speicherposition 0x00000000..
    

    Das Programm funktioniert trotzdem.
    Wie bekomme ich das weg, oder kann man das problemlos ignorieren?

    2. Kann man einem Thread bestimmte Werte übergeben.
    Einen Thread erstellt man ja so:

    void thread() 
    { 
        std::cout << 1 << std::endl; 
    } 
    
    int main() 
    { 
      boost::thread t(thread); 
      t.join(); 
    }
    

    (kurz aus highscore.de kopiert)
    Dabei können in Zeile 8 keine Parameter übergeben werden. Wie kann ich einem Thread dennoch bestimme Werte übergeben?


Anmelden zum Antworten