Threadlaufzeiten von 15 - 16 ms Hiiilfe

RuFFnEcK

Erfahrenes Mitglied
Hallo zusammen,

also ich hab da ein Perfomance Problem!
Und zwar hab ich mal aufgrund von langen Laufzeiten, Zeitmessungen innerhalb der Funktionionsaufrufe durchgeführt...
Ich kam zu dem Ergebnis dass es sich dabei immer um 15 bis 16 millisekunden handelt,
bzw. vielfache davon. Manchmal rutschen Funktionen mit 0 ms durch, aber die Regel ist min.
15 ms. Das kam mir sehr komisch vor und hatte Ursprünglich den Gedanken dass es vielleicht der FTDI Chip ist der 15 - 16 ms puffert und erst dann die Daten weiter gibt...
Aber dann hab ich die Laufzeiten meiner Interpretationsfunktion gemessen und kam zum gleichen Schluss, Schwankungen zwischen 0 und 15 - 16 ms, aber hier war die Regel die 0 ms.
Aber niemals was dazwischen, somit muss es ja am Betriebssystem liegen...
Hierbei arbeiten vier unabhängige Multithreading Komponenten miteinander, so dass die Kommunikationszeiten zwischen 15 und 63 millisekunden schwanken...

Stimmt es dass ein Sleep(0) die in einem Thread übrige Arbeitszeit freigibt?
Wie kann ich diese min. 15 ms Laufzeit reduzieren? Möglichst ohne die Priorität des Threads herauf zu setzen...Was ist beispielsweise mit WaitForSingleObjekt() ?

Ich weiß grad echt nicht mehr weiter dieses Problem zu umgehen, da es forderung ist die Laufzeiten so minimal wie möglich zu halten!

Bin für jede Hilfe dankbar!

PS: Es kann doch nicht sein dass jeder Thread 15 - 16 ms Zeit bekommt, oder?
 
Sorry es scheint ich schreib zu viel, darum hier ne kurzfassung:

- Gibt ein "Sleep(0);" Aufruf innerhalb eines Threads, alle restliche vom Scheduler an den jeweiligen Thread vergebene Zeit frei?

- Wenn nicht gibts es eine Möglichkeit diese mindest Laufzeit eines Threads von 15 - 16 ms reduzieren?

Danke und Gruß

RuFF
 
Hi,
der Messwert kommt durch die Zeitmessfunktion...

Timer in Windows wie WM_TIMER lösen schnellstens mit 15ms aus... schneller geht bei denen nicht. und 15 ms sind auch das was du beobachtest. Dein Code ist also wenigstens gleich schnell bzw noch schneller.

Es gibt aber auch Funktionen, die ms genau auflösen...

Such mal hier im Forum bin mir sicher da gibt es bereits was...

Spontan fallen mir mal die Funktionen timeGetTime und GetTickCount ein. Eine davon macht das glaub ich

Gruß Michael
 
Moin,

meines Wissens ist es die "GetTickCount()" Funktionen um auf Millisekunden genau aufzulösen...
Hatte vorher mit CTime::GetTime() gearbeitet, die aber auch recht viele ressourcen fressen.
GetTickCount() super, aber es macht mir den Eindruck als wären es die Zeitscheiben die Windoof
den Threads zuweist...
Weißt du viell. genaueres in die Richtung?
Der Kommunikationsautomat verschickt Daten nur in einem 15ms Raster, via Scope gemessen und ist ebenso mit den MFC implementiert...

Danke und Gruß

RuFF
 
Hallöchen,

ich fang mal damit an was ich verstanden hab dabon:
Mit "QueryPerformanceCounter" hol ich mir einen aktuellen hochaufgelösten Zeitstempel oder Counter, den hol ich mir am Anfang der Funktion und am Ende, oder?
Dann müsste ich den Ersten von dem Letzten abziehen Und das Ergebnis durch den mit "QueryPerformanceFrequency " ermittelten Frequenz teilen um das ganze in Sekunden zu erhalten?
Dann noch mit 1000 multiplizieren um es in millisekunden zu haben, oder?
Ich hab noch nie mit "LONG_INTEGER" gearbeitet und weiß nicht so recht wie ich die von einander abziehen soll, sofern meine Vermutung überhaupt korrekt ist...
Das ist ja ne Union mit zwei jeweils 32 bit also 4 Byte Werten, ich müsste die dann shiftend
"<<" zusammen addieren, oder? Welcher Datentyp könnte sowas denn aufnehmen?

Grüße und Danke im Vorraus!
 
Das ist ja ne Union mit zwei jeweils 32 bit also 4 Byte Werten
Das stimmt ja so nicht wirklich. Es ist eine union aus einem struct(mit 2 32-Bit Werten) und einem 64-Bit Wert.
Mit den 64-Bit Werten kannst Du ganz normal arbeiten, wie mit long ints auch. Der Compiler kann mir 64-Bit Werten umgehen. Vor der Division solltest du sie aber in double umwandeln (zumindest den Counter-Wert), sonst machst Du eine Ganzzahldivision. Dann wäre die Multiplikation mit 1000 nicht mehr so wirklich sinnvoll.
 
Moin,

ich hätte viell. dazu schreiben sollen, "unteranderem mit 2 ..."
Ich habs hinbekommen, hab in der MSDN ne Anleitung gefunden ;)
Ist ein bisschen umständlich die Benuztung hier mein Code falls es jemand benutzen möchte,
um wirklich genau zu messen! Weil es ist wirklich so dass "GetTickCount()" entweder 0 oder 15-16 ms misst, bzw. vielfache davon!

Ich hab das Beispiel genommen und mir ein paar Funktionen gebastel um diese verwenden zu kömnnen...
Man muss einmal zu Beginn, zum ermitteln der Hardwareunterstützung und der Frequenzermittlung die "DetermineTimer()" Funktion aufrufen, ich machs im Konstruktor von CControl...
Dann gibts die "DetermineElapsedTime(LARGE_INTEGER tStart, LARGE_INTEGER tStop) Funktion, der ich nachdem ich die Zeiten mit "QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount)" ermittelt habe übergebe...

Code:
//Header:
        void DunselFunction() { return; }

	LARGE_INTEGER PerfFreq;      // ticks per second
	int PerfFreqAdjust; // in case Freq is too big
	int OverheadTicks;   // overhead  in calling timer
	bool bUseTimer;

//Implementierung:
void CControl::DetermineTimer()
{
   // Assume the worst
   bUseTimer = false;
   if ( QueryPerformanceFrequency(&PerfFreq) )
      {
      // We can use hires timer, determine overhead
      bUseTimer = true;
      OverheadTicks = 200;
      for ( int i=0; i < 20; i++ )
         {
         LARGE_INTEGER b,e;
         int Ticks;
         QueryPerformanceCounter(&b);
         DunselFunction();
         QueryPerformanceCounter(&e);
         Ticks = e.LowPart - b.LowPart;
         if ( Ticks >= 0 && Ticks < OverheadTicks )
            OverheadTicks = Ticks;
         }
      // See if Freq fits in 32 bits; if not lose some precision
      PerfFreqAdjust = 0;
      int High32 = PerfFreq.HighPart;
      while ( High32 )
         {
         High32 >>= 1;
         PerfFreqAdjust++;
         }
      }
   return;
}

DWORD CControl::DetermineElapsedTime(LARGE_INTEGER tStart, LARGE_INTEGER tStop)
{
	LARGE_INTEGER Freq = PerfFreq;
    int Oht = OverheadTicks;
    int ReduceMag = 0;
    double time;
	DWORD returnValue;			
	// Results are 64 bits but we only do 32
	unsigned int High32 = tStop.HighPart - tStart.HighPart;
	while ( High32 )
	{
		High32 >>= 1;
		ReduceMag++;
	}
	if ( PerfFreqAdjust || ReduceMag )
	{
		if ( PerfFreqAdjust > ReduceMag )
		ReduceMag = PerfFreqAdjust;
		tStart.QuadPart = Int64ShrlMod32(tStart.QuadPart, ReduceMag);
		tStop.QuadPart = Int64ShrlMod32(tStop.QuadPart, ReduceMag);
		Freq.QuadPart = Int64ShrlMod32(Freq.QuadPart, ReduceMag);
		Oht >>= ReduceMag;
	}

	// Reduced numbers to 32 bits, now can do the math
	if ( Freq.LowPart == 0 )
		time = 0.0;
	else
		time = ((double)(tStop.LowPart - tStart.LowPart - Oht)) / Freq.LowPart;
		
	returnValue = time * 1000;
	return returnValue;		
}

Also sieht die Verwendung etwas so aus:

Code:
	LARGE_INTEGER tStartRoutine, tStopRoutine;
	DWORD dwRoutineTime;

    if(bUseTimer)
		QueryPerformanceCounter(&tStartRoutine);

//Aufruf der Funktion dessen Laufzeit ermittelt werden soll...

    if(bUseTimer)
    {
		QueryPerformanceCounter(&tStopRoutine);
		dwRoutineTime = DetermineElapsedTime(tStartRoutine, tStopRoutine);
    }

Vielen Dank euch allen, ihr habt wieder mal sehr geholfen

Grüße
RuFF
 
Zurück