[C] Timer Resolution

Memnoch1337

Cadet 1st Year
Registriert
Apr. 2012
Beiträge
10
Hallo,

ich habe bereits in einem anderen Thread hilfe erfragt(https://www.computerbase.de/forum/threads/echtzeitgarantie-unter-windows-xp.1047641/#post-11836106) und wollte nun einen Lösungsvorschlag ausprobieren.

Daher wollte ich in Eigenarbeit dieses Programm schreiben:
http://www.lucashale.com/timer-resolution/

Wie auch auf der eben genannten Website steht benötigt man folgende Routine für die Umsetzung:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd743626(v=vs.85).aspx

Nun habe ich ein einfaches Programm geschrieben, welches das Prinzip umsetzen soll.

Programm:
Code:
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <time.h>

#define TARGET_RESOLUTION 1         // 1-millisecond target resolution

#pragma comment ( lib, "WinMM.Lib" )

int _tmain(int argc, _TCHAR* argv[])
{
	char str [80];
	int i;
    SYSTEMTIME  now, then;
	TIMECAPS tc;
	UINT     wTimerRes;
	then.wMilliseconds=0;

	if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) //die "geklaute" Routine zur Systemzeitanpassung
	{
		// Error; application can't continue.
		printf("Error; application can't continue.\n");
	}

	wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax); //minimale Resolution finden
	
	if(timeBeginPeriod(wTimerRes) == TIMERR_NOERROR){
			printf("No_Error; Timer running.\n");
			printf("Min: %03d\n",  tc.wPeriodMin); //minimale periodendauer, bei mir 001
			printf("Max: %03d\n",  tc.wPeriodMax); //maximale periodendauer, bei mir 1000000

			for(i=0;i<100;i++){
				GetSystemTime(&now);
				if(then.wMilliseconds != now.wMilliseconds){	//vergleich ob sie sich systemzeit zum letzten durchlauf geändert hat
						printf("%d: Zeit: %02d.%03d\n", i, now.wSecond, now.wMilliseconds); //gib die aktuelle Systemsekunde und Systemmillisekunde aus
						}
				Sleep(1);			//schläft eine milisekunde
				then = now;
			}

			timeEndPeriod(wTimerRes);
	}

	scanf ("%s",str); 
	

	return 0;
}

Ausgabe(gekürzt -- gibts hier irgendwie Spoiler? ):
Code:
No_Error; Timer running.
Min: 001
Max: 1000000
0: Zeit: 40.675
2: Zeit: 40.691
10: Zeit: 40.706
18: Zeit: 40.722
26: Zeit: 40.738
34: Zeit: 40.753
42: Zeit: 40.769
50: Zeit: 40.785
58: Zeit: 40.800
66: Zeit: 40.816
74: Zeit: 40.831
82: Zeit: 40.847
90: Zeit: 40.863
98: Zeit: 40.878
So wie ich das verstanden habe sollte doch nun die Systemzeit jede Millisekunde umschalten, dementsprechend sollte ich 1000 Ausgaben haben und nicht weit weniger. Oder habe ich das Prinzip nicht richtig verstanden?
Ich dachte ich passe die Systemzeit nun so an, dass sie eben nicht mehr alle 10-15 Millisekunden aktuallisiert, sondern jede Millisekunde.

Vielen Dank schonmal!

Gruß,
Memnoch.
 
Zuletzt bearbeitet:
Die von dir gelinkten URLs habe ich nur kurz überflogen.
Dein Problem ist nach wie vor die Auflösung des Timers. Windows "tickt" standardmäßig mit 15,6ms.
Es gibt jetzt mehrere Möglichkeiten dies zu ändern.
Entweder du schreibst deinen eigenen Timer und verwendest PerformanceCounter als Zeitgeber oder benutzt die Win32 API (bzw. die Nt API).

In diesem Artikel findest du eine mögliche Lösung über Performance-Counter.

Solltest du dich für die Win API entscheiden, helfen dir die beiden Methoden NtSetTimerResolution und NtQueryTimerResolution weiter. Beide leider undokumentiert. Es gibt auch noch ein paar offizielle Methoden wie z.B. die QueueTimer (einfach durch die Links hangeln).
Evtl. reicht dir sogar schon ein Call zu timeBeginPeriod aus (den Hinweis auf MSDN beachten, in deinem Code fehlt. z.B. das timeEndPeriod. Ebenfalls solltest du die Methode auf Erfolg prüfen).

Wie auch immer. Das herabsetzen des Timers auf 1ms bringt einige "Nachteile" mit sich, die du berücksichtigen solltest. Ich hatte mal ein Paper von Microsoft (das ich natürlich grad nicht finde), in welchem die Auswirkungen der reduzierte Timer auf z.B. das Power-Management der CPU (C-States funktionieren dann nicht mehr), beschrieben wurden. Hier in dem Dokument wird kurz angedeutet, dass du mit bis zu 25% erhöhtem Energieverbrauch zu rechnen hast.
 
Zuletzt bearbeitet:
danke holy!

ich arbeite mich mal durch und poste etwaige ergebnisse :)

Edit:
Ich hab nun den Code so angepasst, wie du es mir geraten hast. Ich setzte die EndTimePeriod und prüfe die Methode auf Erfolg.(im ersten Post angepasst)
Theoretisch scheint alles zu laufen, praktisch gibt es keine Veränderung. Er fragt immernoch nur alle 15 ms ab.

Ich werde nun mal das mit den Performance-Counter probieren.
Allerdings muss ich dazu den C++ Code auf C migrieren... muss ich erstmal sehen in wie weit das klappt :)
 
Zuletzt bearbeitet:
Memnoch1337 schrieb:
Ich werde nun mal das mit den Performance-Counter probieren.
Allerdings muss ich dazu den C++ Code auf C migrieren... muss ich erstmal sehen in wie weit das klappt :)

Was? Wieso das denn?? Im übrigen ist dein Code (wenn der Code oben gemeinst ist) stilistisch so wie so eher C als C++.
 
Windows hat eben keine sehr genaue Auflösung der Millisekunden, da führt kein Weg vorbei. Es seidenn du willst du nur die Zeit zwischen 2 Punkten messen, dann kannst du den QueryPerformanceCounter nehmen.

Auf welchem Windows hast du das denn getestet? Denn Windows 7 hat glaube ich mittlerweile eine 1ms Auflösung, kann mich aber auch irren.
 
Okay, also ich konnte das Problem zumindest ein wenig umgehen.
Allerdings fasst der Befehl
Code:
GetSystemTime();
die Systemzeit ab... diese wird nur alle 15.6ms aktualisiert... irgendwie führt da auch trotz anpassung des resolution timers kein weg drumrum (warum auch immer).

Allerdings konnte ich nun den umweg über den Befehl
Code:
timeGetTime();
nehmen. Dieser fasst die Zeit an, wie lange das System schon läuft.
Damit bekomme ich auch Zeiten von 1ms unterschied aufgezeigt.

Also das, was ich im Moment erstmal brauche :)

Ich muss leider unter Windows XP arbeiten :/
 
Den hat er nicht programmiert. Der ist im Lieferumfang von C++11 mit dabei. ;)
 
Danke für den Hinweis :)

Aber wenn das wirklich auf C++11 basiert werde ich das sicher nicht in C migireren können.

Und ich bin gezwungen C zu nutzen :/
 

Ähnliche Themen

E
Antworten
5
Aufrufe
6.756
emeraldmine
E
Antworten
6
Aufrufe
1.687
Zurück
Oben