Windows Display driver/manager??

  • Hallo miteinander,

    Ich habe eine etwas unübersichtliche Fragestellung und weiss nicht, wo ich genau anfangen soll:

    Ich automatisiere eine Software, welche für mich Berechnungen durchführt. Für die Vorbereitung der Berechnungen müssen verschiedene Daten in Formulare geschrieben werden und es müssen eine Reihe von Message-boxen (der Software) behandelt werden. Dann erfolgt die Berechnung - währenddem wartet mein (kompiliertes) Script auf ein Ergebnisfenster. Sobald das da ist, werden Ergebnisse verarbeitet und anschliessend geht der Zirkus von vorne los (Formular einfüllen, msg-boxen bearbeiten und wieder rechnen).

    Soweit alles prima - läuft flüssig und Fehlerfrei.

    Um die Rechenleistung optimal zu nutzen, habe ich mehrere Instanzen (insgesamt 40) der Software parallel laufen. Für jede Instanz läuft ein eigenes Script, welches die zugehörigen Fenster, msg-boxen etc. korrekt der "eigenen" Instanz zuornet und diese parallel behandelt.

    Auch alles prima - läuft auch flüssig und Fehlerfrei.

    Das ganze läuft bei mir auf einem separaten Windows Rechner (Intel 18-Kerner mit 40 Programminstanzen und jeweils 40 zugehörigen Scripten). Auf den Rechner greife ich via Remote-Desktop zu.

    Wenn die verschiedenen Instanzen gleichzeitig viele Msg-Boxen anzeigen sehe ich, dass "das System langsam wird". D. h. es geht die Prozessornutzung runter, weil wohl zu viel auf die Bearbeitung am Bildschirm wartet (?). Wenn der "Stau" auf dem Bildschirm nicht so gross ist, habe ich 100% Prozessorlast, wenn aber viel los ist, geht die Prozessornutzung runter.

    Ich habe schon alle Anzeige-eigenschaften so einfach wie möglich eingestellt (also Fensterinhalt nicht mit Fenster verschieben etc.). Nun frage ich mich, ob ich die Abarbeitung der msg-boxen irgendwie beschleunigen kann. Klar kann ich die verschiedenen Sleep-Zeiten in Autoit anpassen, das ist es aber nicht, sondern irgendwo gibt es da einen Stau innerhalb von Windows.

    Mir ist schon klar, dass die Konstellation mit den vielen instanzen eher speziell ist, aber wie gesagt, funktioniert fehlerfrei (hat mich auch 2 Jahre gebraucht, das so hinzukriegen...).

    Hat mir jemand Hinweise, wo ich da eventuell im Windows hingreifen könnte?

    Danke für Eure Hilfe und Grüsse

    -ovik

  • Wenn die verschiedenen Instanzen gleichzeitig viele Msg-Boxen anzeigen sehe ich, dass "das System langsam wird". D. h. es geht die Prozessornutzung runter, weil wohl zu viel auf die Bearbeitung am Bildschirm wartet (?).

    Während eine MsgBox aktiv angezeigt wird, wartet diese Programminstanz auf das schliessen und dieses Warten erzeugt natürlich keine Prozessorlast. Du kannst aber den TimeOut Parameter von MsgBox verwenden um die MsgBox automatisch zu beenden.

    Zitat von AutoIt Hilfe

    Function MsgBox

    Displays a simple message box with optional timeout.

    MsgBox ( flag, "title", "text" [, timeout = 0 [, hwnd]] )

  • Hi,

    du könntest versuchen, nur ein Script auf dieser Maschine laufen zu lassen und dieses (zur Not händisch) nur einem Core zuordnen. Dann eine zweite Instanz deines Scripts starten und auch diesem Core zuordnen. "Irgendwann" wird es dann zwangsläufig zäh werden.....Ich vermute, nach ca. 4-5 Instanzen. Woher ich das weiß? Ausprobiert, mehrmals, mit unterschiedlichen Scripten.

    Das Interessante dabei ist, dass auf EINEM Core VIEL (!) mehr Instanzen flüssig laufen im Vergleich zu einem Mehrkern- oder sogar Mehrprozessorsystem.

    Wie du vermutet hast, liegt das Problem liegt bei Windows. Der Scheduler hat bei einem Einkernprozessor nur die Zeitscheiben für eine Handvoll Threads zu verwalten, das macht der nebenbei im Schlaf...

    Bei Multicore und Multiprozessorsystemen kommt hinzu, dass Windows exzessiv sog. Core-Hopping betreibt, und zwar umso mehr, je stärker die Prozessoren ausgelastet sind. Windows versucht "krampfhaft", die Last möglichst gleichmäßig zu verteilen. Das führt zum bei dir (und auch bei mir) festgestellten Wahnsinn, dass der Scheduler "am Anschlag" läuft, also so viel mit der Verwaltung der Zeitscheiben und des Core-Hoppings zu tun hat, dass die anderen Kerne teilweise wenig bis nichts zu tun haben und sogar in diverse Sleep-Modi fallen....

    Die warten gewissermaßen darauf, wieder vom Scheduler "aktiviert" zu werden.

    Wenn dann auch noch der Speicher (RAM) knapp wird, ist es ganz aus! Dann wird noch auf Teufel komm raus geswappt....

    Nicht umsonst benötigt man "spezielle" Software, um aus den neuen 18- oder 24-Kernern auch Leistung herauszuholen.

    Nichtsdesto trotz könntest du auch versuchen, einem "zäh" laufenden Script mit diversen Tools, beispielsweise dem ProcessExplorer von https://live.sysinternals.com , auf den Zahn zu fühlen. Ggf. "hängt" aber auch deine zu steuernde Software, Grund s.o.

    Einen ersten Überblick würde ich mir mit dem Ressourcenmonitor aus dem Taskmanager verschaffen! Viel Spass dabei :o)

  • Während eine MsgBox aktiv angezeigt wird, wartet diese Programminstanz auf das schliessen und dieses Warten erzeugt natürlich keine Prozessorlast. Du kannst aber den TimeOut Parameter von MsgBox verwenden um die MsgBox automatisch zu beenden.

    Danke, autoBert. Die Messageboxen kommen nicht von AutoIt, sondern vom zu automatisierenden Programm. Mein Script braucht keinerlei Input "von aussen".

    Andy: die Sache mit dem Scheduler könnte hinkommen. Mir ist allerdings nicht klar, was ein Verschieben verursacht: Wenn die Berechnungen lang sind und wenige msg-Boxen vom Programm (nicht AutoIt) komme ich auf 100% CPU-Auslastung. Lang heisst: 5 sek Formulare ausfüllen und msg-boxen bedienen und dann so 10 min. rechnen. Bei 40 Instanzen ist dann "nicht so viel auf dem Bildschirm los". Wenn die Berechnungen kürzer ausfallen, scheint windows zu beschäftigt, wartet oder sonst was. Ich schau mal, womit ich sehe, auf welcher CPU ein Prozess grad läuft und ob der oft wechselt. Wenn das der Fall wäre, könnte ich ja evtl. die CPU-ID fest einstellen....

    Einmal editiert, zuletzt von Ovik (26. November 2018 um 21:27)

  • Hallo nochmal. Ich habe nun versucht, meine Prozesse an einen Prozessor zu binden. Ich habe Rechner mit 4, 8 und 18 Kernen (durch HT, also 8,16 und 36 "Prozessoren"). Ich habe mit der Funktion unten erste Versuche gemacht, aber es gelingt mir nicht, die "affinity Mask" richtig zu setzen. Wie muss der Code aussehen, damit ich bestimmen kann, welchem Prozessor (und eben nur diesem einen) ein Prozess zugeordnet werden soll???

    Also die Funktion

    Code
    ProcessSetAffinity($iProcessID,$iProcessor = 1)

    möchte ich den ProzessID mitgeben und anschliessend, auf welchem Prozessor der Prozess gemappt werden soll. Die funktion erwartet aber schon eine Affinity Mask (glaube ich), von der ich nicht weiss, wie ich die korrekt erstellen soll =O

    Danke schon einmal..

  • Die funktion erwartet aber schon eine Affinity Mask (glaube ich), von der ich nicht weiss, wie ich die korrekt erstellen soll =O

    Steht doch da, wie es geht...

    ;; Inputs:

    ;; iProcessID - the PID of the process to change affinity

    ;; iProcessor - the integer value of the binary affinity bitmask (see below)

  • hmm ok ... sorry, komme dem trotzdem nicht auf die Schliche (evtl. auch zu spät...).

    Ich habe nun in die Funktion folgendes eingebaut:

    Code
        ; translate processornumber to bitmask
        Local $bProcessor = Int("'" & StringReplace(_StringRepeat("0", $NumberCores), $NumberCores - $iProcessor + 1, '1', 1)& "'" )

    und übergebe dann später $bProcessor anstelle von $iProcessor

    Code
        Local $aAffinity = DllCall($hDLL, 'int', 'SetProcessAffinityMask', 'int', $aProcessHandle[0], 'int', $bProcessor)

    Aber wenn ich dann im Taskmgr schaue, sind alle CPU's selektiert. Bei 1 und 2 funktioniert das allerdings prima (habe das in einer VM mit 8 CPU's in der VM laufen) ....

    Kannst du mir hier etwas im Code helfen?

  • Schau mal hier, ob dir das hilft...

  • Danke danke für die Nachtarbeit, Bitnugger :sleeping:!

    Ich hab das nun mit einer längeren Schleife versehen und dann kompiliert. So kann man im ProcessExplorer gut prüfen, welche Kerne verwendet werden.

    Funktioniert leider nicht wie gewünscht: Bei der Anweisung unten wird nur core0 benutzt. Prima.

    Code
    Global $g_bAffinityMask = _UsedCoresToAffinityMask($g_iNumberCores, $iCore01), $g_iUsedCores = @extended ; Nur Core 1 benutzen

    Bei der Anweisung unten wird aber nicht nur core 1 benutzt, sondern 1 und 3 !?

    Code
    Global $g_bAffinityMask = _UsedCoresToAffinityMask($g_iNumberCores, $iCore02), $g_iUsedCores = @extended ; Nur Core 2 benutzen

    Und wenn ich $iCore03 einsetze, dann werden Core 2, 5 und 6 verwendet....

    Irgendwas ist mit der Mask nicht gut?

  • ...doch...alles gut^^

    Du setzt mit der Funktion die ANZAHL der zu benutzenden Cores, bei 3 werden also 3 Cores benutzt. Soweit so gut...

    Um Jetzt den Thread einem (oder mehreren) dieser Prozessoren zuzuordnen , musst du SetThreadAffinityMask verwenden

    //EDIT

    so wie ich das sehe, wird HT (welches sowieso nur virtuell) ist, "abgeschaltet". Wie es sich gehört, wird die volle Core-Performance ausgenutzt! Daher sieht man im Ressourcenmonitor auch nur die Last auf dem jeweils "ersten" Kern, also CPU0, CPU2, CPU4 usw

  • Danke Andy und Bitnugger. Mein Ziel war immer nur, eine PID einem einzigen Prozessor zuzuordnen.

    Wie muss der Code aussehen, damit ich bestimmen kann, welchem Prozessor (und eben nur diesem einen) ein Prozess zugeordnet werden soll???

    Das ist mir nun mit folgender ganz einfachen Funktion gelungen (geht vermutlich noch reduzierter, aber aus meienr pragmatischen Sicht funktioniert das nun):

    Code
    Func ProcessSetAffinity($iProcessID, $g_useCore)
        local $hPID = _WinAPI_OpenProcess($PROCESS_ALL_ACCESS, 0, $iProcessID, True)
        _WinAPI_SetProcessAffinityMask( $hPID, 2 ^ ($g_useCore - 1))
    EndFunc

    Getestet und funktioniert gut. Wie gesagt, mehr als einen core brauch ich ja nicht.

    Danke an alle!

  • Feine Funktion :thumbup:

    Dann lass mal irgendwann von dir hören, inwieweit sich weitere Klarheiten zum Topic ergeben. :)

    Da bin ich sehr gespannt, ich habe in der Firma *tagsüber* (also wenn ca. 30 Rechner am Server angemeldet sind) ähnlichen Trouble mit diversen Excel-VBA-Scripten. Die werden ab und zu schneckenlahm....

    In den meisten dieser Scripte lese ich aus (teilw. mehrere hundert MB großen) *.txt-Dateien und dann wird mit diesen Daten geExcelt, d.h. Excel nur als Darstellung missbraucht. Ich VERMUTE (!), den Usern ist nur beschränkt Arbeitsspeicher zur Verfügung gestellt (lt unserem Admin wird jedem so viel Speicher genehmigt wie er braucht...haha...). Ist der Speicher voll ( bzw. Cachemiss im Dateicache), wird auf die Platte geswapped, bei abwechselndem Öffnen und Schließen von Dateien und permanentem swappen der Supergau... ....denke ich mir. Prüfen kann ich das nicht, unser Admin ist da etwas eigen^^

    Logge ich mich von Zuhause aus ein, Abends spät oder am Wochenende, *schwuppt* alles wie am Schnürchen.

    Für meine Vermutung spricht weiterhin, dass es Scripte gibt, die aus Textdateien lesen und die Ergebnisse anzeigen im Millisekundenbereich, und einige Minuten später bzw. nachdem andere Scripte gelaufen sind, dann mehrere Sekunden brauchen für die identische Abfrage....Läuft dieses Script auf einem Rechner der dieses Script ausschliesslich ( ! ) benutzt, gibt es NIE Wartezeiten:/

  • Tja - ich habe ja das Thema eigentlich auf "Erledigt" gesetzt. Aber das ist es leider nicht. Denn so sehr ich mich nun darüber freue, dass ich die Prozesse den Cores zuordnen kann, erreiche ich damit nicht den gewünschten Effekt. Ich teste das gerade auf meinem 18-Kerner. Ich lasse gerade 36 instanzen parallel laufen (also 36 Instanzen meiner Software und 36 Instanzen der kompilierten AutoIt Steuerungen - jeweils zugeorndet auf einen anderen Kern). Theoretisch müsste das den Prozessor zu 100% auslasten. Tatsächlich werden schlappe 15% (!!) gebraucht. Ich habe die Einstellungen so gewählt, dass sehr viele msg-Boxen bearbeitet werden müssen. Und auf dem Desktop poppen fleissig fenster auf, die sofort abgearbeitet werden. Aber die Fenster werden reichlich "clumsy" angezeigt, also poppen auf und verschwinden irgendwie langsam, man kann fast zuschauen wie sie aufgebaut werden....

    WARUM IST DAS SO LANGSAM??? CPU-Power ist mehr als genug da.

    Wenn ich versuche, andere Fenster anzuklicken, geht das extrem langsam (also die visuelle Bestätigung funktioniert kaum und die Reaktion von Klicks sind ebenfalls entsprechend verlangsamt). Es wirkt irgendwie so als ist hier das Display der Flaschenhals? Zur Erinnerung: ich nutze den computer via Remote-Desktop.

    Gibt es noch ideen, wie ich das beschleunigen kann oder ist das einfach so bei Windows?

  • Irgendwas ist mit der Mask nicht gut?

    In der Tat... war gestern wohl doch schon zu müde. ;)

    In der AutoIt-Hilfe zu _WinAPI_SetProcessAffinityMask steht bei Remarks:

    An affinity mask is a bit mask in which each bit represents a processor on which the threads of the process

    are allowed to run. For example, if you pass a mask of 0x05, processors 1 and 3 are allowed to run.

    In deiner Funktion solltest du das Handle von _WinAPI_OpenProcess aber auch wieder entsorgen und überprüfen, ob $g_useCore im Limit ist!

    Übrigens... mit $g_useCore gibst du nicht die zu verwendenden "Cores" an, sondern die "Logical Processors".

    Hier habe ich noch mal was gebastelt... schau es dir an!

    Einmal editiert, zuletzt von Bitnugger (2. Dezember 2018 um 21:43)

  • Hi,

    Tatsächlich werden schlappe 15% (!!) gebraucht.

    "Gebraucht" ist das Stichwort. Im Sinne von "...es ist nicht mehr Arbeit da...".

    Überleg mal, was DU machen würdest, wenn jemand dir sagen sollte, du müsstest mit weiteren 17 Kollegen in einem Büro sitzen und Telefonanfragen entgegen nehmen, ihr alle zusammen hättet aber nur EINEN Mitarbeiter in der Telefonzentrale, welcher die reinkommenden Gespräche "händisch" entgegennimmt und an euch verteilt. Wenn dann auch nur 5 Leute GLEICHZEITIG die Zentrale anrufen, haben etwas später ALLE anderen nichts mehr zu tun!

    Die Task-Verwaltung innerhalb von Windows funktioniert wie bspw. HIER angerissen.

    Die verteilten Zeitscheiben springen alle 20-120ms von einem Task zum anderen, je nach Prioritätenliste.

    Bei 36 Tasks bleiben dem BS gerade mal 25ms um die gesamte Verwaltung von diesem Task abzuwickeln, inclusive Bildschirmaktualisierung und allen API- und Kernel-Aufrufen. Die Verwaltung deiner Anwendungen zwingt Windows in die Knie, nicht die auf den einzelnen Cores laufenden Programme! Windows selbst rödelt dermaßen im Hintergrund, dass die einzelnen Prozesse nicht schnell genug "Nachschub" bekommen und so "leerlaufen"...

    DAS ist das sahnige Geheimnis von Multitasking/threading! Es ist nur dann effektiv, wenn EIN Task in mehrere Threads aufgeteilt wird und diese dann jeweils (idealerweise) auf einem Core exclusiv (mit 100% Auslastung) laufen.

    Bei den großen Rechenclustern wird daher alles dafür getan, die Verwaltung so effektiv wie möglich zu gestalten.

    Beim "Numbercrunchen" wird das Berechnungsprogramm auf einer CPU gestartet. Diese verteilt die Berechnungen nicht an die 1000 verfügbaren Grafikkarten, denn diese eine CPU könnte die Daten nicht schnell genug "einsammeln", sortieren und aufbereiten. Also gibt es die Berechnung weiter an 10 weitere CPU´s, welche das "einsammeln", sortieren und aufbereiten der Daten von 100 Grafikkarten jeweils "gerade so schaffen".

    Funktioniert das Ganze nicht in der theoretisch maximalen Effizienz, also dann, wenn es immer noch bei der Aufbereitung hakt, dann werden weitere CPU´s zwischengeschaltet. Die Rechnerarchitektur wird VORHER (!!!) auf die maximale Effizienz der Lösung des Problems ausgerichtet! Mit dem Ziel, ALLE Grafikkarten zu 100% auszulasten!

    Bei dir ist es genau umgekehrt. Übertrage dein gesamtes Konzept auf eine 64-Prozessormaschine, und du wirst sehen, dass die Auslastung auf den einzelnen Cores bei 5% rumdümpelt.....

    DEIN Konzept bietet sich wunderbar an, um auf mehrere Rechner mit jeweils eigenem Betriebssystem verteilt zu werden.

    Vor Jahrzehnten schon gab es das als "Bildschirmschoner" für SETI, heute BOINC.

  • Andy: Danke für die Erklärungen. Hab mir den Link auch noch angesehen, bin aber dafür dann doch zu wenig Experte um das im Detail zu verstehen. Was ich (glaube) verstanden zuhaben ist, dass der Scheduler der Flaschenhals ist. Da warten viele Kollegen auf Arbeit, aber der Chef kommt nicht nach die vielen Aufgaben zu verteilen. Die Möglichkeit, das stärker zu verteilen könnte ich natürlich machen, indem ich meinen 18-Kerner in mehrere Instanzen virtualisiere und auf jeder virtuellen Maschine ein eigenes Windows installiere. Das wird mir dann aber zu aufwändig und - wegen der Lizenzen - auch zu teuer. Das hier von mir aufgeführte Szenario mit den 15% ist ein Extremszenario und kommt so sehhhr selten zum Einsatz. Aber ich wollte das einmal besser verstehen, ob ich evtl. etwas übersehe. Habe also verstanden, dass ich hier nichts ändern kann bzw. dann sozusagen alles richtig gemacht habe.

    Noch eine Verständnisfrage: In meinem Szenario ist vermutlich der Prozess, der das Display steuert am Anschlag (denn der ist mit den vielen abzuarbeitenden msg-Boxen voll beschäftigt). Der ist vermutlich nicht in verschiedene Threads parallelisiert, weswegen alle auf den Prozess warten. Damit wäre es wohl nicht der Scheduler, der überfordert ist, sondern eben doch der Window manager? Wenn also MS den Window manager elegant beschleunigen könnte, wäre das alle schneller?

  • @bignugger: Danke auch für Deine Überarbeitung. Das ist natürlich etwas sorgfälter durchprogrammiert, als ich das hätte machen können. Super und schau ich mir gerne an.

  • Ovik , Bitnugger und Andy :

    'Vielen Dank' für die interessanten Ausführungen und Hintergrundinformationen :thumbup:

    Ein unterstützender Hinweis von mir für andere Leser :

    Falls man bei der Ausführung des Skriptes von Bitnugger folgende Meldung erhält :

    ==> The requested action with this object has failed .:

    $aWMI[3] = $objItem.NumberOfEnabledCore

    $aWMI[3] = $objItem^ ERROR

    (wird aufgerufen in : Func _GetProcessors() ... $aWMI[3] = $objItem.NumberOfEnabledCore)

    dann hat das folgenden Hintergrund, siehe :

    https://docs.microsoft.com/de-de/windows/…win32-processor

    -> NumberOfEnabledCore :

    ---> This property is not supported before Windows Server 2016 and Windows 10.

    deutsch :

    Diese Eigenschaft (NumberOfEnabledCore) wird VOR 'Server 2016' und 'Win10' nicht unterstützt

    Wer also z.B. Windows 7 verwendet, muss diese Zeile auskommentieren !

    Falls man zudem Meldungen wie : _WinAPI_OpenProcess(): undefined function

    erhält, dann sollte man statt #include <WinAPIProc.au3> #include <WinAPI.au3> einbinden.

    Diesbzgl. wurden einige Funktionen (zumindest nach der 3.3.14.0) verschoben.

    In der <WinAPIProc.au3> von AutoIt 3.3.14.0 ist _WinAPI_OpenProcess() z.B. nicht aufgeführt.

    Das sind aber keine Fehler in Bitnugger's Skript, sondern ist der Verwendung von älteren AutoIt- bzw. Windowsversionen geschuldet :!:

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

  • $g_iNumberOfCores, $g_iNumberOfEnabledCore und $g_iNumberOfProcessors habe ich nur drin gelassen, falls diese Werte später mal benötigt werden. Aktuell wird nur $g_iNumberOfLogicalProcessors verwendet.

  • Aktuell wird nur $g_iNumberOfLogicalProcessors verwendet.

    Die Eigenschaft NumberOfEnabledCore wird aber bei :

    Case 'Win32_Processor'

    ... $aWMI[3] = $objItem.NumberOfEnabledCore

    verwendet.

    Das reicht ja schon, dass das Skript bei OS kleiner Win10 aus genannten Gründen terminiert.

    Bei Windows 7 (und 8, 8.1 sicher auch) sieht die Konsole wie folgt aus :

    Code
    > @AutoItPID = 1656
    
    CurrentThread = 0xFFFFFFFE
    > @@ Win32_ComputerSystem
    
    "C:\... : ==> The requested action with this object has failed.:
    $aWMI[3] = $objItem.NumberOfEnabledCore
    $aWMI[3] = $objItem^ ERROR
    ->20:56:04 AutoIt3.exe ended.rc:1

    Kommentiert man die betreffende Zeile aus, dann steht in der Konsole :

    Ich wollte mit meinem Beitrag #18 nur darauf hinweisen, nichts beanstanden ;).

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."