[gelöst] Zeitauflösung von Sleep und co. erhöhen?



  • Hi

    Wen du nicht mit Treiberprogrammierung weiterfahren möchtest, kannst du mit SetPriorityClass() ,und SetThreadPriority den Process Priorisieren.

    -> REALTIME_PRIORITY_CLASS

    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);

    []
    Process that has the highest possible priority. The threads of the process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
    [
    ]

    Damit solltest du Auflösungen von 10-12 ms haben.

    lowbyte



  • @_Luckie: Dass Windows eigentlich nicht für sowas gedacht ist, und man mit seinen sleeps auch immer Pech haben kann, und die erst irgendwann zurückkommen können, ist mir klar. Dass das Programm unter XP zu laufen hat, kann ich jetzt aber leider auch nicht ändern.

    @lowbyte_: Ganz ruhig. 😉
    Dass eine höhere Zeitauflösung (1ms und besser) unter Windows auf Anwendungsebene prinzipiell möglich ist, sieht man ja daran, dass man sich mit QueryPerformanceCounter wunderbar eine sehr präzise Zeit ausgeben lassen kann. Nur die präzisen kurzen Schläfchen klappen halt nicht.
    Es sieht so aus, als ginge bei XP nichts in Richtung High Precision Event Timer.



  • Hi

    Lies den Beitrag eins oben. Damit kannst du genauere Auflösungen auf anwendungsebene erreichen.

    gruss lowbyte



  • lowbyte_ schrieb:

    Wen du nicht mit Treiberprogrammierung weiterfahren möchtest, kannst du mit SetPriorityClass() ,und SetThreadPriority den Process Priorisieren.

    -> REALTIME_PRIORITY_CLASS

    Dann sagt ihm aber bitte auch gleich, wo er den Resetknopf am Gehäuse findet.



  • Ich habe deinen Beitrag gelesen, und mir ist klar, dass das Sceduling meinem Thread gegenüber freundlicher wird, wenn ich die Priorität erhöhe.
    Eine Auflösung von 10-12ms würde mir zwar auch nicht reichen, ich habe deinen Vorschlag aber trotzdem mal umgesetzt.

    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    	SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
    	bool waitForTimeChange = true;
    	SYSTEMTIME st;
    	unsigned long timeInMs( 0 );
    	unsigned long timeInMsOld( 0 );
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		GetSystemTime(&st);
    		timeInMsOld = timeInMs;
    		timeInMs = 24*60*1000* st.wHour + 60*1000*st.wMinute + 1000*st.wSecond + st.wMilliseconds;
    		if ( !waitForTimeChange || ( timeInMs != timeInMsOld ) )
    		{
    			printf("%d.%d.%d %d:%d:%d.%d\n" ,st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
    			++outputCount;
    		}
    	}
    	return 0;
    }
    

    Die dazu gehörige Ausgabe sieht so aus:

    25.6.2010 10:43:36.375
    25.6.2010 10:43:36.390
    25.6.2010 10:43:36.406
    25.6.2010 10:43:36.421
    25.6.2010 10:43:36.437
    25.6.2010 10:43:36.453
    25.6.2010 10:43:36.468
    25.6.2010 10:43:36.484
    25.6.2010 10:43:36.500
    25.6.2010 10:43:36.515
    25.6.2010 10:43:36.531
    25.6.2010 10:43:36.546
    25.6.2010 10:43:36.562
    25.6.2010 10:43:36.578
    25.6.2010 10:43:36.593
    25.6.2010 10:43:36.609
    25.6.2010 10:43:36.625
    25.6.2010 10:43:36.640
    25.6.2010 10:43:36.656
    25.6.2010 10:43:36.671
    

    Es bringt also nichts. Warum auch, es war ja eh kein anderer Prozess im Weg, der ordentlich Rechenzeit verbraucht hätte.

    Jetzt möchte ich gerne den Beleg nachliefern, dass es nicht daran liegt, dass meine Ausgabe zuviel Rechenzeit verbraucht:

    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    	bool waitForTimeChange = false;
    	SYSTEMTIME st;
    	unsigned long timeInMs( 0 );
    	unsigned long timeInMsOld( 0 );
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		GetSystemTime(&st);
    		timeInMsOld = timeInMs;
    		timeInMs = 24*60*1000* st.wHour + 60*1000*st.wMinute + 1000*st.wSecond + st.wMilliseconds;
    		if ( !waitForTimeChange || ( timeInMs != timeInMsOld ) )
    		{
    			printf("%d.%d.%d %d:%d:%d.%d\n" ,st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
    			++outputCount;
    		}
    	}
    	return 0;
    }
    

    ->

    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    

    Setze ich jetzt timeBeginPeriod(1); davor, wird es leider auch nicht besser:

    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    	timeBeginPeriod( 1 );
    	bool waitForTimeChange = true;
    	SYSTEMTIME st;
    	unsigned long timeInMs( 0 );
    	unsigned long timeInMsOld( 0 );
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		GetSystemTime(&st);
    		timeInMsOld = timeInMs;
    		timeInMs = 24*60*1000* st.wHour + 60*1000*st.wMinute + 1000*st.wSecond + st.wMilliseconds;
    		if ( !waitForTimeChange || ( timeInMs != timeInMsOld ) )
    		{
    			printf("%d.%d.%d %d:%d:%d.%d\n" ,st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
    			++outputCount;
    		}
    	}
    	timeEndPeriod( 1 );
    	return 0;
    }
    

    ->

    25.6.2010 10:25:56.640
    25.6.2010 10:25:56.656
    25.6.2010 10:25:56.671
    25.6.2010 10:25:56.687
    25.6.2010 10:25:56.703
    25.6.2010 10:25:56.718
    25.6.2010 10:25:56.734
    25.6.2010 10:25:56.750
    25.6.2010 10:25:56.765
    25.6.2010 10:25:56.781
    25.6.2010 10:25:56.796
    25.6.2010 10:25:56.812
    25.6.2010 10:25:56.828
    25.6.2010 10:25:56.843
    25.6.2010 10:25:56.859
    25.6.2010 10:25:56.875
    25.6.2010 10:25:56.890
    25.6.2010 10:25:56.906
    25.6.2010 10:25:56.921
    25.6.2010 10:25:56.937
    

    Und hier noch mein Beispiel mit QueryPerformanceCounter:

    #include <windows.h>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
    	bool waitForTimeChange = true;
    
    	SYSTEMTIME initSystemTime;
    	GetSystemTime(&initSystemTime);
    	unsigned long initSystemTimeInMs = 24*60*1000* initSystemTime.wHour + 60*1000*initSystemTime.wMinute + 1000*initSystemTime.wSecond + initSystemTime.wMilliseconds;
    
    	LARGE_INTEGER PerformanceCounterTicksPerSecond;
    	QueryPerformanceFrequency(&PerformanceCounterTicksPerSecond);
    
    	LARGE_INTEGER PerformanceCounterTicksAtInit;
    	QueryPerformanceCounter(&PerformanceCounterTicksAtInit);
    
    	LARGE_INTEGER performanceCounterActualTicks;
    
    	unsigned long timeInMs( 0 );
    	unsigned long timeInMsOld( 0 );
    
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		QueryPerformanceCounter(&performanceCounterActualTicks);
    		timeInMsOld = timeInMs;
    		timeInMs = static_cast<unsigned long>( ( ( performanceCounterActualTicks.QuadPart - PerformanceCounterTicksAtInit.QuadPart ) / ( PerformanceCounterTicksPerSecond.QuadPart / 1000 ) ) + initSystemTimeInMs);
    		if ( !waitForTimeChange || ( timeInMs != timeInMsOld ) )
    		{
    			cout << ( timeInMs / (24*60*1000) % 60 ) << ":" << ( timeInMs / (60*1000) ) % 60 << ":" << ( timeInMs / 1000 ) % 60 << "." << timeInMs % 1000 << endl;
    			++outputCount;
    		}
    	}
    	timeEndPeriod( 1 );
    	return 0;
    }
    

    ->

    11:47:56.687
    11:47:56.688
    11:47:56.689
    11:47:56.690
    11:47:56.691
    11:47:56.692
    11:47:56.693
    11:47:56.694
    11:47:56.695
    11:47:56.696
    11:47:56.697
    11:47:56.698
    11:47:56.699
    11:47:56.700
    11:47:56.701
    11:47:56.702
    11:47:56.703
    11:47:56.704
    11:47:56.705
    11:47:56.706
    

    So find ich das wunderbar, und werde die Zeit in Zukunft auf so abfragen.
    Mit 4 Millionen aufrufen, die mein normaler Rechner pro Sekunde von dieser Funktion schafft, ist sie auch nicht zu langsam.

    ...

    So, gerade eben habe ich den Vorschlag von geeky umgesetzt.

    #define _WIN32_WINNT 0x0400
    
    #include <windows.h>
    #include <process.h>
    #include <stdio.h>
    
    #include <iostream>
    
    using namespace std;
    
    SYSTEMTIME initSystemTime;
    unsigned long initSystemTimeInMs;
    LARGE_INTEGER PerformanceCounterTicksPerSecond;
    LARGE_INTEGER PerformanceCounterTicksAtInit;
    
    void printPreciseTime()
    {
    	LARGE_INTEGER performanceCounterActualTicks;
    	QueryPerformanceCounter(&performanceCounterActualTicks);
    	unsigned long timeInMs( static_cast<unsigned long>( ( ( performanceCounterActualTicks.QuadPart - PerformanceCounterTicksAtInit.QuadPart ) / ( PerformanceCounterTicksPerSecond.QuadPart / 1000 ) ) + initSystemTimeInMs) );
    	cout << ( timeInMs / (24*60*1000) % 60 ) << ":" << ( timeInMs / (60*1000) ) % 60 << ":" << ( timeInMs / 1000 ) % 60 << "." << timeInMs % 1000 << endl;
    }
    
    int main()
    {
    
    	GetSystemTime(&initSystemTime);
    	initSystemTimeInMs = 24*60*1000* initSystemTime.wHour + 60*1000*initSystemTime.wMinute + 1000*initSystemTime.wSecond + initSystemTime.wMilliseconds;
    	QueryPerformanceFrequency(&PerformanceCounterTicksPerSecond);
    	QueryPerformanceCounter(&PerformanceCounterTicksAtInit);
    
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		HANDLE waitHandle = CreateWaitableTimer(NULL, true, NULL);
    		LARGE_INTEGER DueTime;
    		FILETIME lpSystemTimeAsFileTime;
    		GetSystemTimeAsFileTime( &lpSystemTimeAsFileTime );
    		DueTime.HighPart = lpSystemTimeAsFileTime.dwHighDateTime;
    		DueTime.LowPart = lpSystemTimeAsFileTime.dwLowDateTime;
    		unsigned int waitTimeInMs( outputCount );
    		DueTime.LowPart += outputCount + waitTimeInMs*10*1000 ;
    		cout << "Target wait time in ms: " << waitTimeInMs << endl;
    		cout << "Start: ";
    		printPreciseTime();
    		SetWaitableTimer(waitHandle, &DueTime, 0, NULL, NULL, false);
    		WaitForSingleObject(waitHandle,INFINITE);
    		cout << "Stop: ";
    		printPreciseTime();
    		cout << endl;
    		CloseHandle(waitHandle); 
    		++outputCount;
    	}
    }
    

    ->

    Target wait time in ms: 0
    Start: 11:36:35.765
    Stop: 11:36:35.765
    
    Target wait time in ms: 1
    Start: 11:36:35.765
    Stop: 11:36:35.766
    
    Target wait time in ms: 2
    Start: 11:36:35.766
    Stop: 11:36:35.769
    
    Target wait time in ms: 3
    Start: 11:36:35.769
    Stop: 11:36:35.773
    
    Target wait time in ms: 4
    Start: 11:36:35.773
    Stop: 11:36:35.778
    
    Target wait time in ms: 5
    Start: 11:36:35.778
    Stop: 11:36:35.784
    
    Target wait time in ms: 6
    Start: 11:36:35.784
    Stop: 11:36:35.791
    
    Target wait time in ms: 7
    Start: 11:36:35.791
    Stop: 11:36:35.799
    
    Target wait time in ms: 8
    Start: 11:36:35.799
    Stop: 11:36:35.807
    
    Target wait time in ms: 9
    Start: 11:36:35.807
    Stop: 11:36:35.817
    
    Target wait time in ms: 10
    Start: 11:36:35.817
    Stop: 11:36:35.828
    
    Target wait time in ms: 11
    Start: 11:36:35.828
    Stop: 11:36:35.840
    
    Target wait time in ms: 12
    Start: 11:36:35.840
    Stop: 11:36:35.852
    
    Target wait time in ms: 13
    Start: 11:36:35.852
    Stop: 11:36:35.866
    
    Target wait time in ms: 14
    Start: 11:36:35.866
    Stop: 11:36:35.881
    
    Target wait time in ms: 15
    Start: 11:36:35.881
    Stop: 11:36:35.896
    
    Target wait time in ms: 16
    Start: 11:36:35.896
    Stop: 11:36:35.913
    
    Target wait time in ms: 17
    Start: 11:36:35.913
    Stop: 11:36:35.930
    
    Target wait time in ms: 18
    Start: 11:36:35.930
    Stop: 11:36:35.949
    
    Target wait time in ms: 19
    Start: 11:36:35.949
    Stop: 11:36:35.968
    

    Ja sehr schön! So scheints zu gehen. Vielen Dank, geeky. 🙂
    Meine Version da oben ist natürlich noch alles andere als Vollständigk (Überlauf vom LowPart usw.) aber ich werde mit diesem Ansatz jetzt mal weitermachen.
    Jetzt werde ich mal herausfinden, warum das überhaupt funktioniert, obwohl die Zeit, auf die ich meine Wartezeit aufaddiere ja eigentlich die ungenaue Systemzeit ist. 😉



  • Hi

    Trotzdem solltest du dir überlegen den Prozess zu priorisieren. Wen deine Cpu mal voll ausgelasstet ist, dan wirst du ohne die Priorisierung keine wirkliche echtzeit mehr haben.

    Ansonnsten hatt wohl geeky gut beschriben wie man auf Anwendungsebene echtzeit fahren kann, ohne gleich mit Treiber zu hantieren.

    Lowbyte



  • @Dobi:
    Deine "QueryPerformanceCounter" Zeit wird gegenüber der "echten" Zeit hübsch driften.



  • @lowbyte_:
    Wie wär's mit einfach mal die Fresse halten statt hier Unsinn über Echtzeitfähigkeit abzulassen?



  • @lowbyte_: Echtzeit kann man unter nem normalen Windows sowieso vergessen. Für sowas gibts andere Betriebssysteme. Gelegentliche Verzögerungen würden sowieso durch die Art, wie das Protokoll definiert ist, abgefangen. Auch mit dem ungenauen Sleep passieren keine dramatischen Fehler, es müssen nur manchmal (wenn es zu früh returned) manche Telegramme neu verschickt werden. Wenn sleep(5) länger dauert passiert gar nix, es wird einfach nur Zeit verschwendet, und das finde ich nicht schön.
    Auf jeden Fall möchte ich mich hier herzlich bei dir bedanken. Du hast hier zwar nicht direkt zur Lösung des eigentlichen Problems beigetragen, jedoch wurde der Thread durch deine Beteiligung (zumindest für mich) wesentlich unterhaltsamer. 😉

    @hustbaer: Ok, das wär natürlich nicht so toll. Ich werde die Abweichung mal messen (ist vermutlich aber auch von der CPU abhängig) und dann mal schaun, ob sich da irgendwas mit regelmäßigem syncen machen lässt, oder ob ich die Idee vom PerformanceCounter für meinen Zweck doch begraben muss.



  • hustbaer schrieb:

    @lowbyte_:
    Wie wär's mit einfach mal die Fresse halten statt hier Unsinn über Echtzeitfähigkeit abzulassen?

    Echt jetzt mal ⚠
    Wie sagte meine Lehrerin immer: Ois foisch! Des is ois foisch!



  • Hi

    @hustbär

    Dan möchte ich wissen wiso... Und nicht einfach hier di Fresse gross aufreisen... Möchte akribisch genau wisen wiso, du Held !
    Was verstehst du unter echtzeit? ms oder ns ?

    Lowbyte





  • @lowbyte_: Ein Betriebssystem wird nicht dadurch zum echtzeitfähig, dass die Zeitauflösung auf Planck-Zeit-Genauigkeit kommt.
    Ein Echtzeitbetriebssystem könnte sogar nur auf die Sekunde genau die Zeit ausgeben. Das entscheidende ist, dass es das zuverlässig tut. Das Verhalten muss vorhersagbar sein. Es gibt beispielsweise spezielle Linux-Kernel für soetwas.
    Das, was eine SPS macht, passiert beispielsweise auch in "Echtzeit".
    Unter normalen Desktop-Betriebssystemen kanns einem immer passieren, dass der Rechner gerade mit irgendwas anderen wie z.B. dem leeren des Festplattencaches oder so beschäftigt ist.

    Edith sagt: Mist, GodsHomeboy war schneller. 😉



  • So ein Unfug! Wenn ich z.B. auf meinen Start Button klicke erscheint das Menu in Echtzeit. Es ist für mich keine Verzögerung feststellbar. Das ist ausreichend um von Echtzeit zu sprechen.



  • Hi

    Ich dachte halt wen du ihn so weit priorisierst das er höhere Priorität hat als alle anderen ink. Sysproc.und Treiber, dann könnte man Echzeit auch auf Windows garantieren. Geht dan aber wohl nur über Treiberprogrammierung. Das waren meine Ansichten.

    Lowbyte



  • Hi

    @hustbaer

    Dan kannst du das normal sagen, und nicht gleich mit Beleidigungen um dich werfen. ok?
    Ich denke vom Kleinkind bist du weit empfernt.!
    Dieser Artikel von wiki ist mir natürlich klar.
    Hast mich wohl falsch verstanden.

    @paule8

    Deine Meinung ist falsch..Unter echtzeit versteht man was anderes!

    Lowbyte



  • Wikipedia sagt:

    Der Begriff Echtzeit legt lediglich fest, dass ein System auf ein Ereignis innerhalb eines vorgegebenen Zeitrahmens reagieren muss. Der Begriff sagt nichts über die Geschwindigkeit oder Verarbeitungsleistung eines Systems aus.

    Das ist in meinem Beispiel der Fall.



  • Paule8 schrieb:

    So ein Unfug! Wenn ich z.B. auf meinen Start Button klicke erscheint das Menu in Echtzeit. Es ist für mich keine Verzögerung feststellbar. Das ist ausreichend um von Echtzeit zu sprechen.

    Na dann klick mal auf die Schaltfläche, wenn der Rechner ausgelastet ist, dann ist es vorbei mit deiner "Echtzeit.". Oder hast du noch nie unter Windows darauf gewartet, dass ein Dialog aufgeht?



  • Was hat das mit Windows zu tun? Das ist bei jedem System so. Wenn du z.B. eine SPS auslastest wird sie ihre Zykluszeit überschreiten.



  • Paule8 schrieb:

    Was hat das mit Windows zu tun? Das ist bei jedem System so. Wenn du z.B. eine SPS auslastest wird sie ihre Zykluszeit überschreiten.

    Nein es gibst Betriebsysteme, die dir garantieren von X s (x wesentlich kleiner als 1), auf Ereignis zu reagieren. Solche OS sind im Sicherheitsbereich zu finden. Ein Beispiel Radaranlagen mit QNX (http://www.qnx.com/).


Anmelden zum Antworten