Funktion über Zeitspanne gleichverteilt aufrufen
-
Hallo Gemeinde,
ich hab ein kleines Problem. Ich muss x mal eine Funktion über einer bestimmten Zeitspanne gleichverteilt aufrufen. BSP: die funktion soll in einer Sekunde genau 20000 mal aufgerufen werden. Jetzt tauchen folgende Schwierigkeiten auf. Ich muss erst mal wissen wie lang der funktionsaufruf dauert (Lösung: wahrscheinlich mit dem performance counter). Dann muss ich noch, wie im Beispiel oben (1/20000)s-(zeit für funktionsaufruf) warten. Sleep() bietet aber nur ms an, dh. ich bin mit meinen 1/20000s weit drunter.
Hat jemand eine Idee??
THX,
Vampy
-
Du könntest die Zeit nehmen, die Funktion ausführen, und dann eine Schleife ausführen bis die Zeit weitgenug ist
Bsp.:do{ starttime = gettime() /* funktionen */ while (gettime() - starttime < zeitinterval); } while ( /* ende */ );bei 20000mal pro sekunde müsste gettime() schon im nanosekunden bereich liegen.
-
oder ne zeitschleife. oder rdtsc.
klassisch ist hier eigentlich die zeitschleife und nach 20000 schleifendurchläufen wird an der uhr geschaut, ob man richtig liegt. wenn nicht, wird korrigiert. regelkreis also. nach 10 sekunden ist das ding eingependelt und macht feine gleichverteilte aufrufe.
-
Problem ist sicher, wenn sich die Systemlast während des Betriebes stark ändert.
-
mit apicalls auf hohe prioritaet setzen und fuer die "pausen" usleep() oder etwas equivalentes benutzen?
-
Danke für die vielen Antworten.
@imhotep: gettime() liefert mir die Zeit nur ms-genau, und wie du schon gesagt hast bin ich im ns-Bereich.
@Volkard: wie sieht so eine Zeitschleife aus, kann mir nichts drunter vorstellen
-
#include <clock.h> int n=0,calls_per_second=20000; clock_t t; for(;;) { t=clock(); n+=calls_per_second; while(n>=CLOCKS_PER_SEC) { funktion(); n-=CLOCKS_PER_SEC; } while(clock()<=t); }braucht leider ein bißchen viel cpu-zeit. eine lösung mit Sleep() wäre ebenfalls möglich, aber ich muß jetzt in die heia :p
-
Danke Konfusius.
Da ich aber so wenig CPU wie möglich verbrauchen will/muss hab ich folgendes ausprobiertHANDLE hTimer = NULL; LARGE_INTEGER liDueTime; QueryPerformanceFrequency( (LARGE_INTEGER*) &Frequency); hTimer = CreateWaitableTimer(NULL, TRUE, "WaitableTimer"); int i=0; while(i<30000) { //Berechne Zeit für einen Funktionsaufruf QueryPerformanceCounter(&TU_Start); MyFunction(); QueryPerformanceCounter(&TU_End); //Berechne Zeit die bis zum 1/500-tel Sekunde zu warten ist liDueTime.QuadPart =(long) -(((double)1/500 - (double)(TU_End.QuadPart-TU_Start.QuadPart)/(double)Frequency.QuadPart)*10000000); //Setze Timer if (!SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0)) { printf("SetWaitableTimer failed (%d)\n", GetLastError()); return 2; } //Warte auf Timer if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0) printf("WaitForSingleObject failed (%d)\n", GetLastError()); i++; }Der Code funktioniert auch wunderbar, aber leider nur bis 100 Funktionsaufrufe/sec. Es ist egal ob ich 1/500 1/20000 schreib, der macht immer nur 1/100. woran könnte es liegen??
-
Dein Code:
QueryPerformanceCounter(&TU_Start); MyFunction(); QueryPerformanceCounter(&TU_End);Hat das Problem, dass wahrscheinlich immer eine Zeitdifferenz nahe 0 rauskommt.
Die Granularitaet des Performance Counters kannst Du mittels QueryPerformanceFrequency() abfragen. Sie liegt z.B. bei ca. 600 kHz.
Wenn Deine Funktion schneller ist, bekommst Du als Zeitdifferenz 0.
Du musst also von der Granularitaet ausgehend, die Du mit QueryPerformanceFrequency() abgefragt hast, die Berechnung fuer die Zeitdauer eines Intervalls berechnen.
Da bei Windows die tatsaechliche Granularitaet des Timings zwischen z.B. 600 kHz und 50 Hz liegt, also Dein Thread unter Umstaenden gar nicht rechtzeitig drankommt, wenn der Timer abgelaufen ist, kann der tatsaechliche Rhythmus Deiner Funktionsaufrufe stark schwanken.
Aber probier's ruhig mal aus.
-
TU_End-TU_Start = 14
FrequencyCounter = 3579545
=>3,9111....*10hoch-6 also nicht 0
Ich hab den Process schon mal mit realtime laufen lassen, kommt der gleiche Wert raus. Nie mehr als 100mal pro sekunde. Wenn ich das ganze ohne Timer durchlaufen lass, z.B. in einer Endlosschleife, erreiche ich Werte von bis zu 100000mal/sec, allerdings bei 100% CPU-Last. Ich möchte nun die Last reduzieren indem ich z.B. nur 20000mal/sec die Funktion aufrufe.
-
Vampy20 schrieb:
Ich hab den Process schon mal mit realtime laufen lassen, kommt der gleiche Wert raus. Nie mehr als 100mal pro sekunde. Wenn ich das ganze ohne Timer durchlaufen lass, z.B. in einer Endlosschleife, erreiche ich Werte von bis zu 100000mal/sec, allerdings bei 100% CPU-Last. Ich möchte nun die Last reduzieren indem ich z.B. nur 20000mal/sec die Funktion aufrufe.
Damit hast Du aber das Problem, dass Du nicht vorhersehen kannst, wie schnell Deine Funktion ueberhaupt ausgefuehrt wird, und ob dann z.B. 20000 mal ueberhaupt noch moeglich sind.
Besser ist in dem Fall, Du gibst einfach den Rest Deiner Zeitscheibe ab:
Sleep(0); // Auf Ende der Zeitscheibe wartenDamit sollte die CPU-Last etwas sinken.
Du kannst natuerlich durch verschiedene Messungen feststellen, wie lange Deine Funktion im Durchschnitt braucht, und anhand dessen ausrechnen, wieviel Prozent der Rechenzeit Du beanspruchen willst und dann entsprechend lange warten.
ULONGLONG GetCPUTicks( void ) { _asm { rdtsc } } ULONGLONG GetFuncTicks( void ) { ULONGLONG t0, t1, diff; t0 = GetCPUTicks(); func(); // Deine Funktion t1 = GetCPUTicks(); diff = ti1 - ti0; return diff; } ULONGLONG GetFuncAverageTicks( void ) { // den Test z.B. 100 mal ausfuehren, um einen Mittelwert zu bekommen ULONGLONG sum = 0; for ( int i=0; i < 100; ++i ) { sum += GetFuncTicks(); } return sum / 100U; }Von da aus auf einen Sleep()-Wert zu kommen, musste selber ausrechnen!

-
bin wieder wach

hier nun eine getestete version, die kaum mehr cpu-zeit verbraucht:
#include <windows.h> #include <iostream> using namespace std; void funktion () { cout<<"."; } int main () { unsigned _int64 calls_per_hour=3600, n=0,t,t_prev,dt; SYSTEMTIME systime; GetSystemTime(&systime); SystemTimeToFileTime(&systime,reinterpret_cast<FILETIME*>(&t)); for(;;) { t_prev = t; GetSystemTime(&systime); SystemTimeToFileTime(&systime,reinterpret_cast<FILETIME*>(&t)); dt = (t-t_prev)/10000L; // time in milli-seconds n+=dt*calls_per_hour; while(n>=3600000L) { funktion(); n-=3600000L; } Sleep(3600000L/calls_per_hour); } return 0; }
-
hi, bin im programmiern noch blutiger anfänger un hab da jetzt n ähnliches problem, nur nicht ganz so kompliziert denk ich^^
hier mein programm: einfaches würfelspiel was fragt ob gewürfelt werden soll, nach eingabe "j" wird gewürfelt mit 2 würfeln (random ausgabe). nebenbei soll ne zeitschleife laufen die alle 5minuten nachdem man wieder "j" zum würfeln eingegeben hat nen 3er pasch ausgibt.
dachte da an sowas wie if(time-gepseichertertimestamp>300) mach paschausgabe else random nur mangelts mir an der umsetzung^^do
{
cout << "Wuerfeln? (j/n)";
cin >> würfeln;
if (würfeln == 'j')srand( time(NULL) );
int w1 = rand() % 6 + 1;
int w2 = rand() % 6 + 1;
printf("Wuerfel 1: %d\nWuerfel 2: %d\n%s", w1, w2, (w1==w2) ? "Pasch!\n" : ""); } while (würfeln == 'j');so sieht das zur zeit aus, hoffe mir kann da jemand weiterhelfen

-
Warum verwendest du printf lieber std::cout
srand( time(NULL) ); do { cout << "Wuerfeln? (j/n)"; cin >> würfeln; if (würfeln == 'j') { int w1 = rand() % 6 + 1; int w2 = rand() % 6 + 1; cout << "w1=" << w1 << " und w2=" << w2 << endl; if (w1 == w2) cout << "Pasch!" << endl; } }while (würfeln == 'j');
-
danke dafür schonmal^^ hatte mir den würfelcode aus nem forum geholt, deswegen hab ichs einfach so stehn lassen

-
wie kann ich denn die zeit überhaupt speichern. ich brauch ja erstmal die startzeit nachdem das erste mal gewürfelt wurde.
-
#include <iostream> #include <time.h> // contains clock() using namespace std; int main() { double time1=0.0, tstart; // time measurment variables // read data tstart = clock(); // start // some code time1 += clock() - tstart; // end time1 = time1/CLOCKS_PER_SEC; // rescale to seconds or "/ 1000" cout << " time = " << time1 << " sec." << endl; return 0; }
-
hmm danke aber damit funktionierts irgendwie nich so wirklich

-
willst du boost verwenden?
#include <boost/thread.hpp> class delayer { boost::system_time last_delay; boost::time_duration delay_time; public: delayer(boost::time_duration delay) : last_delay(boost::get_system_time()), delay_time(delay) {} void delay() { last_delay = std::max(last_delay + delay_time, boost::get_system_time()); boost::this_thread::sleep(last_delay); } }; delayer d(boost::posix_time::microseconds(50)); for (;;) { foo(); d.delay(); // Wartet bis die 50 Millisekunden verstrichen sind }
-
Ups, ich habe auf die ursprüngliche Frage geantwortet.