JitterTest.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. /***********************************************************************
  2. *
  3. * Copyright: Daniel Measurement and Control, Inc.
  4. * 9753 Pine Lake Drive
  5. * Houston, TX 77055
  6. *
  7. * Created by: Vipin Malik and Gail Murray
  8. * Released under GPL by permission of Daniel Industries.
  9. *
  10. * This software is licensed under the GPL version 2. Plese see the file
  11. * COPYING for details on the license.
  12. *
  13. * NO WARRANTY: Absolutely no claims of warranty or fitness of purpose
  14. * are made in this software. Please use at your own risk.
  15. *
  16. * Filename: JitterTest.c
  17. *
  18. * Description: Program to be used to measure wake jitter.
  19. * See README file for more info.
  20. *
  21. *
  22. * Revision History:
  23. * $Id: JitterTest.c,v 1.13 2005/11/07 11:15:20 gleixner Exp $
  24. * $Log: JitterTest.c,v $
  25. * Revision 1.13 2005/11/07 11:15:20 gleixner
  26. * [MTD / JFFS2] Clean up trailing white spaces
  27. *
  28. * Revision 1.12 2001/08/10 19:23:11 vipin
  29. * Ready to be released under GPL! Added proper headers etc.
  30. *
  31. * Revision 1.11 2001/07/09 15:35:50 vipin
  32. * Couple of new features:1. The program runs by default as a "regular"
  33. * (SCHED_OTHER) task by default, unless the -p n cmd line parameter is
  34. * specified. It then runs as SCHED_RR at that priority.
  35. * 2. Added ability to send SIGSTOP/SIGCONT to a specified PID. This
  36. * would presumably be the PID of the JFFS2 GC task. SIGSTOP is sent
  37. * before writing to the fs, and a SIGCONT after the write is done.
  38. * 3. The "pad" data now written to the file on the "fs under test" is
  39. * random, not sequential as previously.
  40. *
  41. * Revision 1.10 2001/06/27 19:14:24 vipin
  42. * Now console file to log at can be specified from cmd line. This can enable
  43. * you to run two instances of the program- one logging to the /dev/console
  44. * and another to a regular file (if you want the data) or /dev/null if you don't.
  45. *
  46. * Revision 1.9 2001/06/25 20:21:31 vipin
  47. * This is the latest version, NOT the one last checked in!
  48. *
  49. * Revision 1.7 2001/06/18 22:36:19 vipin
  50. * Fix minor typo that excluded '\n' from msg on console.
  51. *
  52. * Revision 1.6 2001/06/18 21:17:50 vipin
  53. * Added option to specify the amount of data written to outfile each period.
  54. * The regular info is written, but is then padded to the requested size.
  55. * This will enable testing of different sized writes to JFFS fs.
  56. *
  57. * Revision 1.5 2001/06/08 19:36:23 vipin
  58. * All write() are now checked for return err code.
  59. *
  60. * Revision 1.4 2001/06/06 23:10:31 vipin
  61. * Added README file.
  62. * In JitterTest.c: Changed operation of periodic timer to one shot. The timer is now
  63. * reset when the task wakes. This way every "jitter" is from the last time and
  64. * jitters from previous times are not accumulated and screw aroud with our display.
  65. *
  66. * All jitter is now +ve. (as it should be). Also added a "read file" functionality
  67. * to test for jitter in task if we have to read from JFFS fs.
  68. * The program now also prints data to console- where it can be logged, interspersed with
  69. * other "interesting" printk's from the kernel and drivers (flash sector erases etc.)
  70. *
  71. * Revision 1.3 2001/03/01 19:20:39 gmurray
  72. * Add priority scheduling. Shortened name of default output file.
  73. * Changed default interrupt period. Output delta time and jitter
  74. * instead of time of day.
  75. *
  76. * Revision 1.2 2001/02/28 16:20:19 vipin
  77. * Added version control Id and log fields.
  78. *
  79. ***********************************************************************/
  80. /*************************** Included Files ***************************/
  81. #include <stdio.h> /* fopen, printf, fprintf, fclose */
  82. #include <string.h> /* strcpy, strcmp */
  83. #include <stdlib.h> /* exit, atol, atoi */
  84. #include <sys/time.h> /* setitimer, settimeofday, gettimeofday */
  85. #include <time.h> /* time */
  86. #include <signal.h> /* signal */
  87. #include <sched.h> /* sched_setscheduler, sched_get_priority_min,*/
  88. /* sched_get_priority_max */
  89. #include <unistd.h> /* gettimeofday, sleep */
  90. #include <sys/types.h>
  91. #include <sys/stat.h>
  92. #include <fcntl.h>
  93. #include <sys/mman.h>
  94. #define PROGRAM_NAME "JitterTest"
  95. #include "common.h"
  96. /**************************** Enumerations ****************************/
  97. enum timerActions
  98. {
  99. ONESHOT,
  100. AUTORESETTING
  101. };
  102. /****************************** Constants *****************************/
  103. /* Exit error codes */
  104. #define EXIT_FILE_OPEN_ERR (1) /* error opening output file*/
  105. #define EXIT_REG_SIGALRM_ERR (2) /* error registering SIGALRM*/
  106. #define EXIT_REG_SIGINT_ERR (3) /* error registering SIGINT */
  107. #define EXIT_INV_INT_PERIOD (4) /* error invalid int. period*/
  108. #define EXIT_MIN_PRIORITY_ERR (5) /* error, minimum priority */
  109. #define EXIT_MAX_PRIORITY_ERR (6) /* error, maximum priority */
  110. #define EXIT_INV_SCHED_PRIORITY (7) /* error, invalid priority */
  111. #define EXIT_SET_SCHEDULER_ERR (8) /* error, set scheduler */
  112. #define EXIT_PREV_TIME_OF_DAY_ERR (9) /* error, init. prev. */
  113. /* time of day */
  114. #define MAX_FILE_NAME_LEN (32) /* maximum file name length */
  115. #define STRINGS_EQUAL ((int) 0) /* strcmp value if equal */
  116. #define MIN_INT_PERIOD_MILLISEC ( 5L) /* minimum interrupt period */
  117. #define MAX_INT_PERIOD_MILLISEC (5000L) /* maximum interrupt period */
  118. #define DEF_INT_PERIOD_MILLISEC ( 10L) /* default interrupt period */
  119. #define READ_FILE_MESSAGE "This is a junk file. Must contain at least 1 byte though!\n"
  120. /* The user can specify that the program pad out the write file to
  121. a given number of bytes. But a minimum number needs to be written. This
  122. will contain the jitter info.
  123. */
  124. #define MIN_WRITE_BYTES 30
  125. #define DEFAULT_WRITE_BYTES 30
  126. #define MAX_WRITE_BYTES 4096
  127. /* used for gen a printable ascii random # between spc and '~' */
  128. #define MIN_ASCII 32 /* <SPACE> can be char*/
  129. #define MAX_ASCII 126.0 /* needs to be float. See man rand() */
  130. /*----------------------------------------------------------------------
  131. * It appears that the preprocessor can't handle multi-line #if
  132. * statements. Thus, the check on the default is divided into two
  133. * #if statements.
  134. *---------------------------------------------------------------------*/
  135. #if (DEF_INT_PERIOD_MILLISEC < MIN_INT_PERIOD_MILLISEC)
  136. #error *** Invalid default interrupt period. ***
  137. #endif
  138. #if (DEF_INT_PERIOD_MILLISEC > MAX_INT_PERIOD_MILLISEC)
  139. #error *** Invalid default interrupt period. ***
  140. #endif
  141. #define TRUE 1 /* Boolean true value */
  142. #define FALSE 0
  143. /* Time conversion constants. */
  144. #define MILLISEC_PER_SEC (1000L) /* milliseconds per second */
  145. #define MICROSEC_PER_MILLISEC (1000L) /* microsecs per millisec */
  146. #define MICROSEC_PER_SEC (1000000L) /* microsecs per second */
  147. #define PRIORITY_POLICY ((int) SCHED_RR) /* If specified iwth "-p" */
  148. /************************** Module Variables **************************/
  149. static char OutFileName[MAX_FILE_NAME_LEN+1]; /* output file name */
  150. static char LogFile[MAX_FILE_NAME_LEN+1] = "/dev/console"; /* default */
  151. static char ReadFile[MAX_FILE_NAME_LEN+1]; /* This file is read. Should
  152. contain at least 1 byte */
  153. static int WriteBytes = DEFAULT_WRITE_BYTES; /* pad out file to these many bytes. */
  154. static int Fd1; /* fd where the above buffer if o/p */
  155. static int Cfd; /* fd to console (or file specified) */
  156. static int Fd2; /* fd for the ReadFile */
  157. static int DoRead = FALSE; /* should we attempt to ReadFile?*/
  158. static long InterruptPeriodMilliSec; /* interrupt period, millisec */
  159. static int MinPriority; /* minimum scheduler priority */
  160. static int MaxPriority; /* maximum scheduler priority */
  161. static int RequestedPriority; /* requested priority */
  162. static struct itimerval ITimer; /* interrupt timer structure */
  163. static struct timeval PrevTimeVal; /* previous time structure */
  164. static struct timeval CurrTimeVal; /* current time structure */
  165. static long LastMaxDiff = 0; /* keeps track of worst jitter encountered */
  166. static int GrabKProfile = FALSE; /* To help determine system bottle necks
  167. this parameter can be set. This causes
  168. the /proc/profile file to be read and
  169. stored in unique filenames in current
  170. dir, and indication to be o/p on the
  171. /dev/console also.
  172. */
  173. static long ProfileTriggerMSecs = 15000l; /* Jitter time in seconds that triggers
  174. a snapshot of the profile to be taken
  175. */
  176. static int SignalGCTask = FALSE; /* should be signal SIGSTOP/SIGCONT to gc task?*/
  177. static int GCTaskPID;
  178. static int RunAsRTTask = FALSE; /* default action unless priority is
  179. specified on cmd line */
  180. /********************* Local Function Prototypes **********************/
  181. void HandleCmdLineArgs(int argc, char *argv[]);
  182. void SetFileName(char * pFileName);
  183. void SetInterruptPeriod(char * pASCIIInterruptPeriodMilliSec);
  184. void SetSchedulerPriority(char * pASCIISchedulerPriority);
  185. void PrintVersionInfo(void);
  186. void PrintHelpInfo(void);
  187. int Write(int fd, void *buf, size_t bytes, int lineNo);
  188. void InitITimer(struct itimerval * pITimer, int action);
  189. /* For catching timer interrupts (SIGALRM). */
  190. void AlarmHandler(int sigNum);
  191. /* For catching Ctrl+C SIGINT. */
  192. void SignalHandler(int sigNum);
  193. /***********************************************************************
  194. * main function
  195. * return: exit code
  196. ***********************************************************************/
  197. int main(
  198. int argc,
  199. char *argv[])
  200. {
  201. struct sched_param schedParam;
  202. int mypri;
  203. char tmpBuf[200];
  204. strcpy(OutFileName,"jitter.dat");
  205. InterruptPeriodMilliSec = MIN_INT_PERIOD_MILLISEC;
  206. /* Get the minimum and maximum priorities. */
  207. MinPriority = sched_get_priority_min(PRIORITY_POLICY);
  208. MaxPriority = sched_get_priority_max(PRIORITY_POLICY);
  209. if (MinPriority == -1) {
  210. printf("\n*** Unable to get minimum priority. ***\n");
  211. exit(EXIT_MIN_PRIORITY_ERR);
  212. }
  213. if (MaxPriority == -1) {
  214. printf("\n*** Unable to get maximum priority. ***\n");
  215. exit(EXIT_MAX_PRIORITY_ERR);
  216. }
  217. /* Set requested priority to minimum value as default. */
  218. RequestedPriority = MinPriority;
  219. HandleCmdLineArgs(argc, argv);
  220. if(mlockall(MCL_CURRENT|MCL_FUTURE) < 0){
  221. printf("Could not lock task into memory. Bye\n");
  222. perror("Error");
  223. }
  224. if(RunAsRTTask){
  225. /* Set the priority. */
  226. schedParam.sched_priority = RequestedPriority;
  227. if (sched_setscheduler(
  228. 0,
  229. PRIORITY_POLICY,
  230. &schedParam) != (int) 0) {
  231. printf("Exiting: Unsuccessful sched_setscheduler.\n");
  232. close(Fd1);
  233. exit(EXIT_SET_SCHEDULER_ERR);
  234. }
  235. /* Double check as I have some doubts that it's really
  236. running at realtime priority! */
  237. if((mypri = sched_getscheduler(0)) != RequestedPriority)
  238. {
  239. printf("Not running with request priority %i. running with priority %i instead!\n",
  240. RequestedPriority, mypri);
  241. }else
  242. {
  243. printf("Running with %i priority. Good!\n", mypri);
  244. }
  245. }
  246. /*------------------------- Initializations --------------------------*/
  247. if((Fd1 = open(OutFileName, O_RDWR|O_CREAT|O_SYNC, S_IRWXU)) <= 0)
  248. {
  249. perror("Cannot open outfile for write:");
  250. exit(1);
  251. }
  252. /* If a request is made to read from a specified file, then create that
  253. file and fill with junk data so that there is something there to read.
  254. */
  255. if(DoRead)
  256. {
  257. if((Fd2 = open(ReadFile, O_RDWR|O_CREAT|O_SYNC|O_TRUNC, S_IRWXU)) <= 0)
  258. {
  259. perror("cannot open read file:");
  260. exit(1);
  261. }else
  262. {
  263. /* Don't really care how much we write here */
  264. if(write(Fd2, READ_FILE_MESSAGE, strlen(READ_FILE_MESSAGE)) < 0)
  265. {
  266. perror("Problems writing to readfile:");
  267. exit(1);
  268. }
  269. lseek(Fd2, 0, SEEK_SET); /* position back to byte #0 */
  270. }
  271. }
  272. /* Also log output to console. This way we can capture it
  273. on a serial console to a log file.
  274. */
  275. if((Cfd = open(LogFile, O_WRONLY|O_SYNC)) <= 0)
  276. {
  277. perror("cannot open o/p logfile:");
  278. exit(1);
  279. }
  280. /* Set-up handler for periodic interrupt. */
  281. if (signal(SIGALRM, &AlarmHandler) == SIG_ERR) {
  282. printf("Couldn't register signal handler for SIGALRM.\n");
  283. sprintf(tmpBuf,
  284. "Couldn't register signal handler for SIGALRM.\n");
  285. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  286. close(Fd1);
  287. exit(EXIT_REG_SIGALRM_ERR);
  288. }
  289. /* Set-up handler for Ctrl+C to exit the program. */
  290. if (signal(SIGINT, &SignalHandler) == SIG_ERR) {
  291. printf("Couldn't register signal handler for SIGINT.\n");
  292. sprintf(tmpBuf,
  293. "Couldn't register signal handler for SIGINT.\n");
  294. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  295. close(Fd1);
  296. exit(EXIT_REG_SIGINT_ERR);
  297. }
  298. printf("Press Ctrl+C to exit the program.\n");
  299. printf("Output File: %s\n", OutFileName);
  300. printf("Scheduler priority: %d\n", RequestedPriority);
  301. sprintf(tmpBuf, "\nScheduler priority: %d\n",
  302. RequestedPriority);
  303. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  304. Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__);
  305. printf("Interrupt period: %ld milliseconds\n",
  306. InterruptPeriodMilliSec);
  307. sprintf(tmpBuf, "Interrupt period: %ld milliseconds\n",
  308. InterruptPeriodMilliSec);
  309. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  310. Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__);
  311. fflush(0);
  312. /* Initialize the periodic timer. */
  313. InitITimer(&ITimer, ONESHOT);
  314. /* Initialize "previous" time. */
  315. if (gettimeofday(&PrevTimeVal, NULL) != (int) 0) {
  316. printf("Exiting - ");
  317. printf("Unable to initialize previous time of day.\n");
  318. sprintf(tmpBuf, "Exiting - ");
  319. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  320. sprintf(tmpBuf,
  321. "Unable to initialize previous time of day.\n");
  322. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  323. }
  324. /* Start the periodic timer. */
  325. setitimer(ITIMER_REAL, &ITimer, NULL);
  326. while(TRUE) { /* Intentional infinite loop. */
  327. /* Sleep for one second. */
  328. sleep((unsigned int) 1);
  329. }
  330. /* Just in case. File should be closed in SignalHandler. */
  331. close(Fd1);
  332. close(Cfd);
  333. return 0;
  334. }
  335. /***********************************************************************
  336. * SignalHandler
  337. * This is a handler for the SIGINT signal. It is assumed that the
  338. * SIGINT is due to the user pressing Ctrl+C to halt the program.
  339. * output: N/A
  340. ***********************************************************************/
  341. void SignalHandler(
  342. int sigNum)
  343. {
  344. char tmpBuf[200];
  345. /* Note sigNum not used. */
  346. (void)sigNum;
  347. printf("Ctrl+C detected. Worst Jitter time was:%fms.\nJitterTest exiting.\n",
  348. (float)LastMaxDiff/1000.0);
  349. sprintf(tmpBuf,
  350. "\nCtrl+C detected. Worst Jitter time was:%fms\nJitterTest exiting.\n",
  351. (float)LastMaxDiff/1000.0);
  352. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  353. Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__);
  354. close(Fd1);
  355. close(Cfd);
  356. exit(0);
  357. }
  358. /*
  359. A snapshot of the /proc/profile needs to be taken.
  360. This is stored as a new file every time, and the
  361. stats reset by doing a (any) write to the /proc/profile
  362. file.
  363. */
  364. static void doGrabKProfile(int jitterusec, char *fileName)
  365. {
  366. int fdSnapshot;
  367. int fdProfile;
  368. int readBytes;
  369. char readBuf[4096];
  370. (void)jitterusec;
  371. if((fdSnapshot = open(fileName, O_WRONLY | O_CREAT, S_IRWXU)) < 0)
  372. {
  373. fprintf(stderr, "Could not open file %s.\n", fileName);
  374. perror("Error:");
  375. return;
  376. }
  377. if((fdProfile = open("/proc/profile", O_RDWR)) < 0)
  378. {
  379. fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n");
  380. close(fdSnapshot);
  381. return;
  382. }
  383. while((readBytes = read(fdProfile, readBuf, sizeof(readBuf))) > 0)
  384. {
  385. int writeBytes = write(fdSnapshot, readBuf, readBytes);
  386. if (writeBytes != readBytes) {
  387. perror("write error");
  388. break;
  389. }
  390. }
  391. close(fdSnapshot);
  392. if(write(fdProfile, readBuf, 1) != 1)
  393. {
  394. perror("Could Not clear profile by writing to /proc/profile:");
  395. }
  396. close(fdProfile);
  397. }/* end doGrabKProfile()*/
  398. /*
  399. Call this routine to clear the kernel profiling buffer /proc/profile
  400. */
  401. static void clearProfileBuf(void){
  402. int fdProfile;
  403. char readBuf[10];
  404. if((fdProfile = open("/proc/profile", O_RDWR)) < 0)
  405. {
  406. fprintf(stderr, "Could not open file /proc/profile. Make sure you booted with profile=2\n");
  407. return;
  408. }
  409. if(write(fdProfile, readBuf, 1) != 1)
  410. {
  411. perror("Could Not clear profile by writing to /proc/profile:");
  412. }
  413. close(fdProfile);
  414. }/* end clearProfileBuf() */
  415. /***********************************************************************
  416. * AlarmHandler
  417. * This is a handler for the SIGALRM signal (due to the periodic
  418. * timer interrupt). It prints the time (seconds) to
  419. * the output file.
  420. * output: N/A
  421. ***********************************************************************/
  422. void AlarmHandler(
  423. int sigNum) /* signal number (not used) */
  424. {
  425. long timeDiffusec; /* diff time in micro seconds */
  426. long intervalusec;
  427. char tmpBuf[MAX_WRITE_BYTES];
  428. int cntr;
  429. char padChar;
  430. static int profileFileNo = 0;
  431. char profileFileName[150];
  432. static int seedStarter = 0; /* carries over rand info to next time
  433. where time() will be the same as this time
  434. if invoked < 1sec apart.
  435. */
  436. (void)sigNum;
  437. if (gettimeofday(&CurrTimeVal, NULL) == (int) 0) {
  438. /*----------------------------------------------------------------
  439. * Compute the elapsed time between the current and previous
  440. * time of day values and store the result.
  441. *
  442. * Print the elapsed time to the output file.
  443. *---------------------------------------------------------------*/
  444. timeDiffusec = (long)(((((long long)CurrTimeVal.tv_sec) * 1000000L) + CurrTimeVal.tv_usec) -
  445. (((long long)PrevTimeVal.tv_sec * 1000000L) + PrevTimeVal.tv_usec));
  446. sprintf(tmpBuf," %f ms ", (float)timeDiffusec/1000.0);
  447. intervalusec = InterruptPeriodMilliSec * 1000L;
  448. timeDiffusec = timeDiffusec - intervalusec;
  449. sprintf(&tmpBuf[strlen(tmpBuf)]," %f ms", (float)timeDiffusec/1000.0);
  450. /* should we send a SIGSTOP/SIGCONT to the specified PID? */
  451. if(SignalGCTask){
  452. if(kill(GCTaskPID, SIGSTOP) < 0){
  453. perror("error:");
  454. }
  455. }
  456. /* Store some historical #'s */
  457. if(labs(timeDiffusec) > LastMaxDiff)
  458. {
  459. LastMaxDiff = labs(timeDiffusec);
  460. sprintf(&tmpBuf[strlen(tmpBuf)],"!");
  461. if((GrabKProfile == TRUE) && (ProfileTriggerMSecs < (labs(timeDiffusec)/1000)))
  462. {
  463. sprintf(profileFileName, "JitterTest.profilesnap-%i", profileFileNo);
  464. /* go and grab the kernel performance profile. */
  465. doGrabKProfile(timeDiffusec, profileFileName);
  466. profileFileNo++; /* unique name next time */
  467. /* Say so on the console so that a marker gets put in the console log */
  468. sprintf(&tmpBuf[strlen(tmpBuf)],"<Profile saved in file:%s>",
  469. profileFileName);
  470. }
  471. }
  472. sprintf(&tmpBuf[strlen(tmpBuf)],"\n"); /* CR for the data going out of the console */
  473. Write(Cfd, tmpBuf, strlen(tmpBuf), __LINE__);
  474. /* The "-1" below takes out the '\n' at the end that we appended for the msg printed on
  475. the console.*/
  476. sprintf(&tmpBuf[strlen(tmpBuf)-1]," PadBytes:");
  477. /* Now pad the output file if requested by user. */
  478. if(WriteBytes > MIN_WRITE_BYTES)
  479. {
  480. /* start from a new place every time */
  481. srand(time(NULL) + seedStarter);
  482. /* already written MIN_WRITE_BYTES by now */
  483. for(cntr = strlen(tmpBuf); cntr < WriteBytes - 1 ; cntr++) /* "-1" adj for '\n' at end */
  484. {
  485. /* don't accept any # < 'SPACE' */
  486. padChar = (char)(MIN_ASCII+(int)((MAX_ASCII-(float)MIN_ASCII)*rand()/(RAND_MAX+1.0)));
  487. /*
  488. padChar = (cntr % (126-33)) + 33;
  489. */
  490. tmpBuf[cntr] = padChar;
  491. }
  492. seedStarter = tmpBuf[cntr-1]; /* save for next time */
  493. tmpBuf[cntr] = '\n'; /* CR for the data going into the outfile. */
  494. tmpBuf[cntr+1] = '\0'; /* NULL terminate the string */
  495. }
  496. /* write out the entire line to the output file. */
  497. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  498. /* Read a byte from the specified file */
  499. if(DoRead)
  500. {
  501. cntr = read(Fd2, tmpBuf, 1);
  502. if (cntr < 0)
  503. perror("read error");
  504. lseek(Fd2, 0, SEEK_SET); /* back to start */
  505. }
  506. /* Start the periodic timer again. */
  507. setitimer(ITIMER_REAL, &ITimer, NULL);
  508. /* Update previous time with current time. */
  509. PrevTimeVal.tv_sec = CurrTimeVal.tv_sec;
  510. PrevTimeVal.tv_usec = CurrTimeVal.tv_usec;
  511. }
  512. else {
  513. sprintf(tmpBuf, "gettimeofday error \n");
  514. Write(Fd1, tmpBuf, strlen(tmpBuf), __LINE__);
  515. printf("gettimeofday error \n");
  516. }
  517. /* now clear the profiling buffer */
  518. if(GrabKProfile == TRUE){
  519. clearProfileBuf();
  520. }
  521. /* should we send a SIGSTOP/SIGCONT to the specified PID? */
  522. if(SignalGCTask){
  523. if(kill(GCTaskPID, SIGCONT) < 0){
  524. perror("error:");
  525. }
  526. }
  527. return;
  528. }
  529. /***********************************************************************
  530. * InitITimer
  531. * This function initializes the 'struct itimerval' structure whose
  532. * address is passed to interrupt every InterruptPeriodMilliSec.
  533. * output: N/A
  534. ***********************************************************************/
  535. void InitITimer(
  536. struct itimerval * pITimer, /* pointer to interrupt timer struct*/
  537. int action) /* ONESHOT or autosetting? */
  538. {
  539. long seconds; /* seconds portion of int. period */
  540. long microSeconds; /* microsec. portion of int. period */
  541. /*--------------------------------------------------------------------
  542. * Divide the desired interrupt period into its seconds and
  543. * microseconds components.
  544. *-------------------------------------------------------------------*/
  545. if (InterruptPeriodMilliSec < MILLISEC_PER_SEC) {
  546. seconds = 0L;
  547. microSeconds = InterruptPeriodMilliSec * MICROSEC_PER_MILLISEC;
  548. }
  549. else {
  550. seconds = InterruptPeriodMilliSec / MILLISEC_PER_SEC;
  551. microSeconds =
  552. (InterruptPeriodMilliSec - (seconds * MILLISEC_PER_SEC)) *
  553. MICROSEC_PER_MILLISEC;
  554. }
  555. /* Initialize the interrupt period structure. */
  556. pITimer->it_value.tv_sec = seconds;
  557. pITimer->it_value.tv_usec = microSeconds;
  558. if(action == ONESHOT)
  559. {
  560. /* This will (should) prevent the timer from restarting itself */
  561. pITimer->it_interval.tv_sec = 0;
  562. pITimer->it_interval.tv_usec = 0;
  563. }else
  564. {
  565. pITimer->it_interval.tv_sec = seconds;
  566. pITimer->it_interval.tv_usec = microSeconds;
  567. }
  568. return;
  569. }
  570. /***********************************************************************
  571. * HandleCmdLineArgs
  572. * This function handles the command line arguments.
  573. * output: stack size
  574. ***********************************************************************/
  575. void HandleCmdLineArgs(
  576. int argc, /* number of command-line arguments */
  577. char *argv[]) /* ptrs to command-line arguments */
  578. {
  579. int argNum; /* argument number */
  580. if (argc > (int) 1) {
  581. for (argNum = (int) 1; argNum < argc; argNum++) {
  582. /* The command line contains an argument. */
  583. if ((strcmp(argv[argNum],"--version") == STRINGS_EQUAL) ||
  584. (strcmp(argv[argNum],"-v") == STRINGS_EQUAL)) {
  585. /* Print version information and exit. */
  586. PrintVersionInfo();
  587. exit(0);
  588. }
  589. else if ((strcmp(argv[argNum],"--help") == STRINGS_EQUAL) ||
  590. (strcmp(argv[argNum],"-h") == STRINGS_EQUAL) ||
  591. (strcmp(argv[argNum],"-?") == STRINGS_EQUAL)) {
  592. /* Print help information and exit. */
  593. PrintHelpInfo();
  594. exit(0);
  595. }
  596. else if ((strcmp(argv[argNum],"--file") == STRINGS_EQUAL) ||
  597. (strcmp(argv[argNum],"-f") == STRINGS_EQUAL)) {
  598. /* Set the name of the output file. */
  599. ++argNum;
  600. if (argNum < argc) {
  601. SetFileName(argv[argNum]);
  602. }
  603. else {
  604. printf("*** Output file name not specified. ***\n");
  605. printf("Default output file name will be used.\n");
  606. }
  607. }
  608. else if ((strcmp(argv[argNum],"--time") == STRINGS_EQUAL) ||
  609. (strcmp(argv[argNum],"-t") == STRINGS_EQUAL)) {
  610. /* Set the interrupt period. */
  611. ++argNum;
  612. if (argNum < argc) {
  613. SetInterruptPeriod(argv[argNum]);
  614. }
  615. else {
  616. printf("*** Interrupt period not specified. ***\n");
  617. printf("Default interrupt period will be used.\n");
  618. }
  619. }
  620. else if ((strcmp(argv[argNum],"--priority") ==
  621. STRINGS_EQUAL) ||
  622. (strcmp(argv[argNum],"-p") == STRINGS_EQUAL)) {
  623. /* Set the scheduler priority. */
  624. ++argNum;
  625. if (argNum < argc) {
  626. SetSchedulerPriority(argv[argNum]);
  627. }
  628. else {
  629. printf("*** Scheduler priority not specified. ***\n");
  630. printf("Default scheduler priority will be used.\n");
  631. }
  632. }
  633. else if ((strcmp(argv[argNum],"--readfile") ==
  634. STRINGS_EQUAL) ||
  635. (strcmp(argv[argNum],"-r") == STRINGS_EQUAL)) {
  636. /* Set the file to read*/
  637. ++argNum;
  638. strncpy(ReadFile, argv[argNum], sizeof(ReadFile));
  639. DoRead = TRUE;
  640. }
  641. else if ((strcmp(argv[argNum],"--write_bytes") ==
  642. STRINGS_EQUAL) ||
  643. (strcmp(argv[argNum],"-w") == STRINGS_EQUAL)) {
  644. /* Set the file to read*/
  645. ++argNum;
  646. WriteBytes = atoi(argv[argNum]);
  647. if(WriteBytes < MIN_WRITE_BYTES)
  648. {
  649. printf("Writing less than %i bytes is not allowed. Bye.\n",
  650. MIN_WRITE_BYTES);
  651. exit(0);
  652. }
  653. }
  654. else if ((strcmp(argv[argNum],"--consolefile") ==
  655. STRINGS_EQUAL) ||
  656. (strcmp(argv[argNum],"-c") == STRINGS_EQUAL)) {
  657. /* Set the file to log console log on. */
  658. ++argNum;
  659. strncpy(LogFile, argv[argNum], sizeof(LogFile) - 1);
  660. LogFile[sizeof(LogFile) - 1] = '\0';
  661. }
  662. else if ((strcmp(argv[argNum],"--grab_kprofile") ==
  663. STRINGS_EQUAL))
  664. {
  665. /* We will read the /proc/profile file on configurable timeout */
  666. GrabKProfile = TRUE;
  667. ++argNum;
  668. /* If the jittter is > this #, then the profile is grabbed. */
  669. ProfileTriggerMSecs = (long) atoi(argv[argNum]);
  670. if(ProfileTriggerMSecs <= 0){
  671. printf("Illegal value for profile trigger threshold.\n");
  672. exit(0);
  673. }
  674. }
  675. else if ((strcmp(argv[argNum],"--siggc") ==
  676. STRINGS_EQUAL))
  677. {
  678. /* We will SIGSTOP/SIGCONT the specified pid */
  679. SignalGCTask = TRUE;
  680. ++argNum;
  681. GCTaskPID = atoi(argv[argNum]);
  682. if(ProfileTriggerMSecs <= 0){
  683. printf("Illegal value for JFFS(2) GC task pid.\n");
  684. exit(0);
  685. }
  686. }
  687. else {
  688. /* Unknown argument. Print help information and exit. */
  689. printf("Invalid option %s\n", argv[argNum]);
  690. printf("Try 'JitterTest --help' for more information.\n");
  691. exit(0);
  692. }
  693. }
  694. }
  695. return;
  696. }
  697. /***********************************************************************
  698. * SetFileName
  699. * This function sets the output file name.
  700. * output: N/A
  701. ***********************************************************************/
  702. void SetFileName(
  703. char * pFileName) /* ptr to desired output file name */
  704. {
  705. size_t fileNameLen; /* file name length (bytes) */
  706. /* Check file name length. */
  707. fileNameLen = strlen(pFileName);
  708. if (fileNameLen > (size_t) MAX_FILE_NAME_LEN) {
  709. printf("File name %s exceeds maximum length %d.\n",
  710. pFileName, MAX_FILE_NAME_LEN);
  711. exit(0);
  712. }
  713. /* File name length is OK so save the file name. */
  714. strcpy(OutFileName, pFileName);
  715. return;
  716. }
  717. /***********************************************************************
  718. * SetInterruptPeriod
  719. * This function sets the interrupt period.
  720. * output: N/A
  721. ***********************************************************************/
  722. void SetInterruptPeriod(
  723. char * /* ptr to desired interrupt period */
  724. pASCIIInterruptPeriodMilliSec)
  725. {
  726. long period; /* interrupt period */
  727. period = atol(pASCIIInterruptPeriodMilliSec);
  728. if ((period < MIN_INT_PERIOD_MILLISEC) ||
  729. (period > MAX_INT_PERIOD_MILLISEC)) {
  730. printf("Invalid interrupt period: %ld ms.\n", period);
  731. exit(EXIT_INV_INT_PERIOD);
  732. }
  733. else {
  734. InterruptPeriodMilliSec = period;
  735. }
  736. return;
  737. }
  738. /***********************************************************************
  739. * SetSchedulerPriority
  740. * This function sets the desired scheduler priority.
  741. * output: N/A
  742. ***********************************************************************/
  743. void SetSchedulerPriority(
  744. char * pASCIISchedulerPriority) /* ptr to desired scheduler priority*/
  745. {
  746. int priority; /* desired scheduler priority value */
  747. priority = atoi(pASCIISchedulerPriority);
  748. if ((priority < MinPriority) ||
  749. (priority > MaxPriority)) {
  750. printf("Scheduler priority %d outside of range [%d, %d]\n",
  751. priority, MinPriority, MaxPriority);
  752. exit(EXIT_INV_SCHED_PRIORITY);
  753. }
  754. else {
  755. RequestedPriority = priority;
  756. RunAsRTTask = TRUE; /* We shall run as a POSIX real time task */
  757. }
  758. return;
  759. }
  760. /***********************************************************************
  761. * PrintVersionInfo
  762. * This function prints version information.
  763. * output: N/A
  764. ***********************************************************************/
  765. void PrintVersionInfo(void)
  766. {
  767. common_print_version();
  768. printf("Copyright (c) 2001, Daniel Industries, Inc.\n");
  769. return;
  770. }
  771. /***********************************************************************
  772. * PrintHelpInfo
  773. * This function prints help information.
  774. * output: N/A
  775. ***********************************************************************/
  776. void PrintHelpInfo(void)
  777. {
  778. printf("Usage: JitterTest [options]\n");
  779. printf(" *** Requires root privileges. ***\n");
  780. printf("Option:\n");
  781. printf(" [-h, --help, -?] Print this message and exit.\n");
  782. printf(" [-v, --version] ");
  783. printf( "Print the version number of JitterTest and exit.\n");
  784. printf(" [-f FILE, --file FILE] Set output file name to FILE. Typically you would put this on the fs under test\n");
  785. printf(" [-c FILE, --consolefile] Set device or file to write the console log to.\n\tTypically you would set this to /dev/console and save it on another computer.\n");
  786. printf(" [-w BYTES, --write_bytes BYTES Write BYTES to FILE each period.\n");
  787. printf(" [-r FILE, --readfile FILE] Also read 1 byte every cycle from FILE. FILE will be created and filled with data.\n");
  788. printf(" [-t <n>, --time <n>] ");
  789. printf( "Set interrupt period to <n> milliseconds.\n");
  790. printf(" ");
  791. printf( "Range: [%ld, %ld] milliseconds.\n",
  792. MIN_INT_PERIOD_MILLISEC, MAX_INT_PERIOD_MILLISEC);
  793. printf(" [-p <n>, --priority <n>] ");
  794. printf( "Set scheduler priority to <n>.\n");
  795. printf(" ");
  796. printf( "Range: [%d, %d] (higher number = higher priority)\n",
  797. MinPriority, MaxPriority);
  798. printf(" [--grab_kprofile <THRESHOLD in ms>] Read the /proc/profile if jitter is > THRESHOLD and store in file.\n");
  799. printf(" [--siggc <PID>] Before writing to fs send SIGSTOP to PID. After write send SIGCONT\n");
  800. return;
  801. }
  802. /* A common write that checks for write errors and exits. Pass it __LINE__ for lineNo */
  803. int Write(int fd, void *buf, size_t bytes, int lineNo)
  804. {
  805. int err;
  806. err = write(fd, buf, bytes);
  807. if(err < bytes)
  808. {
  809. printf("Write Error at line %i! Wanted to write %zu bytes, but wrote only %i bytes.\n",
  810. lineNo, bytes, err);
  811. perror("Write did not complete. Error. Bye:"); /* show error from errno. */
  812. exit(1);
  813. }
  814. return err;
  815. }/* end Write*/