// 周期実行試験プログラム // 設定個所: Pentium 以降のCPUの場合 USE_RDTSC を #define する // // 試験条件 main() // A) 処理の性質 // 1) Dummy(定数); 処理量の変動がない // 2) Dummy(乱数); 処理量が変動する // B) 休眠時間の算出法 // 1) 特定時間休眠=処理量の変動があまりない場合 // 2) 現在時間を元に休眠量を算定 // 3) 一旦 usleep することで、休眠量計算の精度向上 // // プログラム引数: // 実行時に引数があった場合、それを周期とする #include #include #include #include #include // Pentium 以降なら #define //#define USE_RDTSC // 現在の時間/分解能を得る #ifdef USE_RDTSC #define TickPerMSEC 461.93e3 inline unsigned long long int GetTick(void) { unsigned int h,l; /* read Pentium cycle counter */ __asm__(".byte 0x0f,0x31" :"=a" (l), "=d" (h)); return ((unsigned long long int)h<<32)|l; } #else // not pentium #define TickPerMSEC 1.0e3 inline unsigned long long int GetTick(void) { struct timeval tv; gettimeofday(&tv,NULL); return (unsigned long long int)tv.tv_sec*1000000+tv.tv_usec; } #endif // 周期時間計測 #define DATALEN 10000 unsigned long long period_last=0; unsigned long long period_rec[DATALEN]; int period_c=0,period_f=0; void CycleProfiler(void) { unsigned long long now; now=GetTick(); if(period_last==0) { period_last=now; return; } period_rec[period_c]=now-period_last; period_c++; if(period_c>=DATALEN) { period_c-=DATALEN; period_f=1; } period_last=now; } void WriteCycleProfiler(char *filename) { FILE *fp; int i,j=0; fp=fopen(filename,"w"); if(fp==NULL) return; if(period_f) { for(i=period_c;i1) w=atoi(argv[1]); while(1) { if(nw>0) usleep(nw*1000); CycleProfiler(); st=GetTick(); //Dummy(1); // 処理量普遍 Dummy(random()%3+1); // 処理量変化 now=GetTick(); // 方法0:固定休眠:処理時間が変動しない場合はこれでもよい nw=w-1; // 方法1:処理にかかった時間から休眠時間を逆算 nw=w-(now-st)/TickPerMSEC; // 方法2:ギリギリのところの精度を向上 usleep(10); // 一旦休眠 now=GetTick(); // タイマ割り込み直後の可能性大 nw=w-(now-st)/TickPerMSEC-0.2; } };