[gelöst] Zeitauflösung von Sleep und co. erhöhen?
-
Falsch. Das war vor 15 Jahren so.
Nein, das ist mit Win2000 und XP noch heute so!
8auf den Rest der Antwort werde ich jetzt mal nicht eingehen.)
-
moetan schrieb:
Falsch. Das war vor 15 Jahren so.
Nein, das ist mit Win2000 und XP noch heute so!
Ich benutze genau jetzt XP und es ist nicht der Fall.
-
Zum Echtzeitverhalten schreib ich mal nichts, ich will ja noch ein wenig leben...
Quatsch. Es wird nicht sicherer, weil man die CPU seltener weggezogen kriegt! Im Gegenzeil, frische Zeitscheibenabschnitte sind langlebiger.
Das Problem ist aber doch nur die schlechte Auflösung der Windows Funktionen! Wenn kein anderer thread die zeit braucht hat man sie.
Inwiefern hält das das Windows davon ab, meinen Prozess von der CPU zu nehmen?
Wohl kaum, aber man kann besser mit sowas umgehen bzw. recht gut optimieren. Aber soweit würde ich dann auch nicht gehen.
-
Ich benutze genau jetzt XP und es ist nicht der Fall.
du hast seit über einer Woche keinen Neustart gemacht und es läuft immer noch stabil und einigermaßen schnell? Das wäre echt ein Wunder!
-
mraka schrieb:
Das Problem ist aber doch nur die schlechte Auflösung der Windows Funktionen! Wenn kein anderer thread die zeit braucht hat man sie.
moetan hatte anscheinend immer genug Zeit, daß Windows immer rechtzeitig antworten konnte (außer es hat mal neu gebootet). Es geht also wohl nirgends um 15ms. Da halte ich es für eine gute Idee, oft zu Sleepen, das gibt dem Windows mehr Gelegenheit, die komischen Privatsachen gerade dann zu machen, wenn ich gerade nichts zu tun habe, es mich also nicht verlangsamt.
Nehme ich alle Prozessorzeit für mich, dann riskiere ich, daß Windows irgendwann die Nase voll hat und was macht, obwohl ich auch was machen will.
-
moetan schrieb:
du hast seit über einer Woche keinen Neustart gemacht und es läuft immer noch stabil und einigermaßen schnell? Das wäre echt ein Wunder!
Keine Auslagerungsdatei, keine Viren, kein Virenscanner, ich arbeite nie als Admin, es ist erst ca ein Jahr alt, die Terabyteplatte ist nur zu 16% voll.
Im Moment ist die Uptime kleiner als eine Woche, weil ich öfters mal zum Linux auf der anderen Platte umgebootet habe. Aber ich habe nie gebootet, weil er langsam geworden wäre und abstürzen tut er auch nicht. In der Küche habe ich einen XP-Rechner stehen, der macht nur einen auf Fileserver. Mal nachgucken...
Ähm, leichter gesagt als getan, wie frage ich denn die uptime ab?
edit: Habs gefunden.C:\irgendwo>net statistics server Serverstatistik für \\IRGENDWER Statistik seit 6/15/2010 6:37 PM ...
-
Ich dachte es geht gerade drum unter 15ms zu kommen???
Windows teilt immer die verfügbare Zeit unter allen Threads auf. Es braucht kein Sleep oder so!Das Sleep ist nur da um Windows mitzuteilen das man einige Zeit nichts zu tun hat. Das ist normalerweise sinnvoll weil andere Threads diese Zeit nutzen können. Es gibt aber eine minimale Zeit(bei XP wohl so um die 15ms). Wenn man also wie in diesem Fall gar keine anderen Threads hat die wirklich die Zeit brauchen macht es ja gar keinen Sinn.
-
Wir sprechen hier von Extremsituationen, da hat jeder seine eigene Meinung. Jedenfalls ist Windows für sowas ganz sicher nicht gedacht. Ich würde dann auch eher zum Mikrocontroller raten. Da kann kein anderer Thread dazwischen kommen.
-
Ich glaube moetan meinte industrielle Anwendungen. Da hat Windows permanent ordentlich was zu tun und nach 1-2 Wochen wird es deutlich langsamer. Deshalb startet man normalerweise immer am WE neu und hat diese Montagsprobleme nicht.
-
@hustbaer: Danke. Hab gerade mal deinen code ausprobiert, auch auf nem anderen Rechner und da dann mit VC 2010 express, aber unter 15ms komme ich trotzdem nicht, obwohl ( timeBeginPeriod(min) == TIMERR_NOERROR ) bei mir auch true ist. Der Bill ist mal wieder so fies zu mir.
Ich werd dann nochmal berichten, wie schlimm die Abweichung mit dem Performance-Counter ist und was meine weiteren Test von Geekys Sleep-Variante ergeben.@Microcontrollervorschlag: Ja, es mag sein, dass es elegantere Lösungen für diese Sache gibt, aber die mir vorgegebene Hardwarekonfiguration ist nun schon vielfach vorhanden und lässt sich aus Kostengründen deshalb nicht mehr ändern.
@loybyte: ><(({°>
-
ich stand vor dem gleichen Problem und habe aufgegeben. Man kann mit einem Multicore Prozessor nicht mehr unter die 15ms kommen. Jedenfalls nicht einigermaßen sicher. Oder hat sich noch eine brauchbare Lösung gefunden?
-
was hat das mit der CPU zu tun? Das ist doch eine Sache die Windows regelt?
-
Mir wurde mehrfach berichtet das man mit einer "normalen" CPU deutlich unter die 15ms kommt. Warum das so ist und ob es wirklich so ist kann ich nicht erklären. Es ist mir sowiso ein Rätsel wie Windows es bei jedem Thread jeder Anwendung schaffen kann mit dieser Präzision immer genau die 15ms einzuhalten.
-
Das dürfte dann wohl eine Sache der Hardware sein. Aber wenn das wirklich so ist wird Windows nur feststellen das die entsprechende CPU vorhanden ist und dann so reagieren.
Deine "Idee" wäre das jeder Thread jeder Anwendung genau 15ms(oder weniger)wartet. Das hat man aber idr nicht.
-
Hier ein paar Hilfsfunktionen die ich mir mal geschrieben hatte.
void sleep(double usleept) { if(usleept >= 0) { // Nur wenn zu schlafen ist struct timeval tv; tv.tv_sec = floor(usleept); tv.tv_usec = fround((usleept - floor(usleept)) * 1000000); // s -> us // 500 ms = 500 000 us; fd_set dummy; SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); FD_ZERO(&dummy); FD_SET(s, &dummy); select(0, NULL, NULL, &dummy, &tv); closesocket(s); } } bool setcyclefrequency( double frequency, bool noadjustment /*= false*/ ) { // Es muss ein Core ausgesucht werden als Zeitgeber HANDLE hProcess = GetCurrentProcess(); m_dwAffinityMask = 0; DWORD dwSystemAffinityMask = 0; GetProcessAffinityMask(hProcess, &m_dwAffinityMask, &dwSystemAffinityMask); unsigned int iProzessor = 0; for(iProzessor = 0; iProzessor < sizeof(m_dwAffinityMask)*8; iProzessor) { DWORD dwAffinityMask = m_dwAffinityMask & (((DWORD)1) << iProzessor); if(dwAffinityMask) { m_dwAffinityMask = dwAffinityMask; break; // Ersten Prozessor wählen } } if(!m_dwAffinityMask) return false; // Immer auf gleichem Prozessor ausführen m_hThread = GetCurrentThread(); DWORD oldAffinityMask = SetThreadAffinityMask(m_hThread, m_dwAffinityMask); if(!oldAffinityMask) return false; if(!QueryPerformanceFrequency((LARGE_INTEGER*)&m_clockFrequency)) // zeit in clocks pro sekunde return false; if(frequency > 1000000) // Max 1 MHz / 1 us (theoretisch) // real max 10 KHz frequency = 1000000; m_cycleTime = (1.0/frequency); // Zeit in Clocks die ein Zyklus dauert m_bAdjustment = !noadjustment; SetThreadAffinityMask(m_hThread, oldAffinityMask); return resetcycle(); } bool waitfornextcycle() { m_cycles++; // Immer auf gleichem Prozessor ausführen DWORD oldAffinityMask = SetThreadAffinityMask(m_hThread, m_dwAffinityMask); if(!oldAffinityMask) return false; if(!m_bInit) { m_dwstartTime = m_dwcurrentTime = GetTickCount(); m_bInit = true; } else m_dwcurrentTime = GetTickCount(); if(m_dwcurrentTime < m_dwlastTime) // Overflow in Timer ~50 Tage { m_dwstartTime = m_dwcurrentTime; m_dwlastTime = ((~(DWORD)0) - m_dwlastTime) + m_dwcurrentTime; m_cycles = 1; } if(0 == m_cycles) // Overflow Zykluszähler (Taktabhängig) { m_dwstartTime = m_dwcurrentTime; m_cycles = 1; } // Overflow des PerfomanceCounters sind bei 3 Ghz circa 180 Jahre also nicht relevant -> Rückfall auf 10 ms Auflösung in diesem Fall da hohe differenz if(!QueryPerformanceCounter((LARGE_INTEGER*)&m_currentTime)) return false; double QPCdiff = m_currentTime - m_lastTime; double GTCdiff = m_dwcurrentTime - m_dwlastTime; double GTCdiff_total = m_dwcurrentTime - m_dwstartTime; QPCdiff /= m_clockFrequency; // clocks -> s GTCdiff /= 1000; // ms -> s GTCdiff_total /= 1000; // ms -> s if(fabs(QPCdiff - GTCdiff) > 0.1) // mehr als 100ms Differenz -> QPC springt oder overflowt, GTC timer Korrektur (bei langen Zyklusdauern) // Oder Overflow im Performance Counter QPCdiff = GTCdiff; // Fallback zu ms Auflösung in diesem Takt m_nLostCycles = fround((GTCdiff_total / m_cycleTime) - m_cycles); // Genauerer Sleeps über BSD Socket select Funktion if(m_nLostCycles <= 0 || !m_bAdjustment) { // Nur wenn momentan keine Takte verlorengegangen sind oder Takt Korrektur abgeschaltet ist double usleept = m_cycleTime - QPCdiff; // Berechne wie lange wir schlafen duerfen anhand der vergangen Zeit leit letzem Aufruf sleep(usleept); } // Frequenz hier nochmal aktualisieren angeblich ändert sie sich trotz MSDN trotzdem manchmal if(!QueryPerformanceFrequency((LARGE_INTEGER*)&m_clockFrequency)) // zeit in clocks pro sekunde return false; m_dwlastTime = GetTickCount(); if(!QueryPerformanceCounter((LARGE_INTEGER*)&m_lastTime)) return false; SetThreadAffinityMask(m_hThread, oldAffinityMask); return true; } bool resetcycle() { m_lastTime = 0; m_currentTime = 0; m_dwstartTime = 0; m_dwlastTime = 0; m_dwcurrentTime = 0; m_bInit = false; m_cycles = 0; m_nLostCycles = 0; // Immer auf gleichem Prozessor ausführen DWORD oldAffinityMask = SetThreadAffinityMask(m_hThread, m_dwAffinityMask); if(!oldAffinityMask) return false; m_dwlastTime = GetTickCount(); if(!QueryPerformanceCounter((LARGE_INTEGER*)&m_lastTime)) return false; SetThreadAffinityMask(m_hThread, oldAffinityMask); return true; } bool isfrequencyok() { // Wenn wir über 10 Sekunden nachhängen ist der Takt nicht realisierbar oder es wird debuggt etc. bool bRet = ((double)m_nLostCycles * m_cycleTime) <= 10.0; if(!bRet) return false; return bRet; }
Frequenz einmal initialisieren und dann einfach immer waitfornextcycle aufrufen sorgt dafür das die Frequenz eingehalten wird. (bei mir bis zu 10 khz)
-
ganz schön heftig...aber 10Khz wären schon 0,1ms...
Muß ich mir mal in Ruhe anschauen.
-
So, nochmal vielen Dank für die Hilfe und ich wollte mitteilen, wie es für mich ausgegangen ist.
Das normale Sleep ist für meine Zwecke schon genau genug (1ms).
Für die genaue Uhrzeit verwende ich das hier:
http://msdn.microsoft.com/en-us/magazine/cc163996.aspx
Dazu die kleine Änderung, dass ich immer QueryPerformanceCounter benutze, weil TSC trotz vorherigem CPUID auf manchen alten Athlons Käse ausgibt.