alarm.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /***********************************************************************
  6. ** 1996 - Netscape Communications Corporation
  7. **
  8. ** Name: alarmtst.c
  9. **
  10. ** Description: Test alarms
  11. **
  12. ** Modification History:
  13. ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
  14. ** The debug mode will print all of the printfs associated with this test.
  15. ** The regress mode will be the default mode. Since the regress tool limits
  16. ** the output to a one line status:PASS or FAIL,all of the printf statements
  17. ** have been handled with an if (debug_mode) statement.
  18. ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been updated to
  19. ** recognize the return code from tha main program.
  20. ***********************************************************************/
  21. /***********************************************************************
  22. ** Includes
  23. ***********************************************************************/
  24. #include "prlog.h"
  25. #include "prinit.h"
  26. #include "obsolete/pralarm.h"
  27. #include "prlock.h"
  28. #include "prlong.h"
  29. #include "prcvar.h"
  30. #include "prinrval.h"
  31. #include "prtime.h"
  32. /* Used to get the command line option */
  33. #include "plgetopt.h"
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #if defined(XP_UNIX)
  37. #include <sys/time.h>
  38. #endif
  39. static PRIntn debug_mode;
  40. static PRIntn failed_already=0;
  41. static PRThreadScope thread_scope = PR_LOCAL_THREAD;
  42. typedef struct notifyData {
  43. PRLock *ml;
  44. PRCondVar *child;
  45. PRCondVar *parent;
  46. PRBool pending;
  47. PRUint32 counter;
  48. } NotifyData;
  49. static void Notifier(void *arg)
  50. {
  51. NotifyData *notifyData = (NotifyData*)arg;
  52. PR_Lock(notifyData->ml);
  53. while (notifyData->counter > 0)
  54. {
  55. while (!notifyData->pending) {
  56. PR_WaitCondVar(notifyData->child, PR_INTERVAL_NO_TIMEOUT);
  57. }
  58. notifyData->counter -= 1;
  59. notifyData->pending = PR_FALSE;
  60. PR_NotifyCondVar(notifyData->parent);
  61. }
  62. PR_Unlock(notifyData->ml);
  63. } /* Notifier */
  64. /***********************************************************************
  65. ** PRIVATE FUNCTION: ConditionNotify
  66. ** DESCRIPTION:
  67. **
  68. ** INPUTS: loops
  69. ** OUTPUTS: None
  70. ** RETURN: overhead
  71. ** SIDE EFFECTS:
  72. **
  73. ** RESTRICTIONS:
  74. ** None
  75. ** MEMORY: NA
  76. ** ALGORITHM:
  77. **
  78. ***********************************************************************/
  79. static PRIntervalTime ConditionNotify(PRUint32 loops)
  80. {
  81. PRThread *thread;
  82. NotifyData notifyData;
  83. PRIntervalTime timein, overhead;
  84. timein = PR_IntervalNow();
  85. notifyData.counter = loops;
  86. notifyData.ml = PR_NewLock();
  87. notifyData.child = PR_NewCondVar(notifyData.ml);
  88. notifyData.parent = PR_NewCondVar(notifyData.ml);
  89. thread = PR_CreateThread(
  90. PR_USER_THREAD, Notifier, &notifyData,
  91. PR_GetThreadPriority(PR_GetCurrentThread()),
  92. thread_scope, PR_JOINABLE_THREAD, 0);
  93. overhead = PR_IntervalNow() - timein; /* elapsed so far */
  94. PR_Lock(notifyData.ml);
  95. while (notifyData.counter > 0)
  96. {
  97. notifyData.pending = PR_TRUE;
  98. PR_NotifyCondVar(notifyData.child);
  99. while (notifyData.pending) {
  100. PR_WaitCondVar(notifyData.parent, PR_INTERVAL_NO_TIMEOUT);
  101. }
  102. }
  103. PR_Unlock(notifyData.ml);
  104. timein = PR_IntervalNow();
  105. (void)PR_JoinThread(thread);
  106. PR_DestroyCondVar(notifyData.child);
  107. PR_DestroyCondVar(notifyData.parent);
  108. PR_DestroyLock(notifyData.ml);
  109. overhead += (PR_IntervalNow() - timein); /* more overhead */
  110. return overhead;
  111. } /* ConditionNotify */
  112. static PRIntervalTime ConditionTimeout(PRUint32 loops)
  113. {
  114. PRUintn count;
  115. PRIntervalTime overhead, timein = PR_IntervalNow();
  116. PRLock *ml = PR_NewLock();
  117. PRCondVar *cv = PR_NewCondVar(ml);
  118. PRIntervalTime interval = PR_MillisecondsToInterval(50);
  119. overhead = PR_IntervalNow() - timein;
  120. PR_Lock(ml);
  121. for (count = 0; count < loops; ++count)
  122. {
  123. overhead += interval;
  124. PR_ASSERT(PR_WaitCondVar(cv, interval) == PR_SUCCESS);
  125. }
  126. PR_Unlock(ml);
  127. timein = PR_IntervalNow();
  128. PR_DestroyCondVar(cv);
  129. PR_DestroyLock(ml);
  130. overhead += (PR_IntervalNow() - timein);
  131. return overhead;
  132. } /* ConditionTimeout */
  133. typedef struct AlarmData {
  134. PRLock *ml;
  135. PRCondVar *cv;
  136. PRUint32 rate, late, times;
  137. PRIntervalTime duration, timein, period;
  138. } AlarmData;
  139. static PRBool AlarmFn1(PRAlarmID *id, void *clientData, PRUint32 late)
  140. {
  141. PRStatus rv = PR_SUCCESS;
  142. PRBool keepGoing, resetAlarm;
  143. PRIntervalTime interval, now = PR_IntervalNow();
  144. AlarmData *ad = (AlarmData*)clientData;
  145. PR_Lock(ad->ml);
  146. ad->late += late;
  147. ad->times += 1;
  148. keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
  149. PR_TRUE : PR_FALSE;
  150. if (!keepGoing) {
  151. rv = PR_NotifyCondVar(ad->cv);
  152. }
  153. resetAlarm = ((ad->times % 31) == 0) ? PR_TRUE : PR_FALSE;
  154. interval = (ad->period + ad->rate - 1) / ad->rate;
  155. if (!late && (interval > 10))
  156. {
  157. interval &= (now & 0x03) + 1;
  158. PR_WaitCondVar(ad->cv, interval);
  159. }
  160. PR_Unlock(ad->ml);
  161. if (rv != PR_SUCCESS)
  162. {
  163. if (!debug_mode) {
  164. failed_already=1;
  165. }
  166. else {
  167. printf("AlarmFn: notify status: FAIL\n");
  168. }
  169. }
  170. if (resetAlarm)
  171. {
  172. ad->rate += 3;
  173. ad->late = ad->times = 0;
  174. if (PR_ResetAlarm(id, ad->period, ad->rate) != PR_SUCCESS)
  175. {
  176. if (!debug_mode) {
  177. failed_already=1;
  178. }
  179. else {
  180. printf("AlarmFn: Resetting alarm status: FAIL\n");
  181. }
  182. keepGoing = PR_FALSE;
  183. }
  184. }
  185. return keepGoing;
  186. } /* AlarmFn1 */
  187. static PRIntervalTime Alarms1(PRUint32 loops)
  188. {
  189. PRAlarm *alarm;
  190. AlarmData ad;
  191. PRIntervalTime overhead, timein = PR_IntervalNow();
  192. PRIntervalTime duration = PR_SecondsToInterval(3);
  193. PRLock *ml = PR_NewLock();
  194. PRCondVar *cv = PR_NewCondVar(ml);
  195. ad.ml = ml;
  196. ad.cv = cv;
  197. ad.rate = 1;
  198. ad.times = loops;
  199. ad.late = ad.times = 0;
  200. ad.duration = duration;
  201. ad.timein = PR_IntervalNow();
  202. ad.period = PR_SecondsToInterval(1);
  203. alarm = PR_CreateAlarm();
  204. (void)PR_SetAlarm(
  205. alarm, ad.period, ad.rate, AlarmFn1, &ad);
  206. overhead = PR_IntervalNow() - timein;
  207. PR_Lock(ml);
  208. while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
  209. PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
  210. }
  211. PR_Unlock(ml);
  212. timein = PR_IntervalNow();
  213. (void)PR_DestroyAlarm(alarm);
  214. PR_DestroyCondVar(cv);
  215. PR_DestroyLock(ml);
  216. overhead += (PR_IntervalNow() - timein);
  217. return duration + overhead;
  218. } /* Alarms1 */
  219. static PRBool AlarmFn2(PRAlarmID *id, void *clientData, PRUint32 late)
  220. {
  221. PRBool keepGoing;
  222. PRStatus rv = PR_SUCCESS;
  223. AlarmData *ad = (AlarmData*)clientData;
  224. PRIntervalTime interval, now = PR_IntervalNow();
  225. PR_Lock(ad->ml);
  226. ad->times += 1;
  227. keepGoing = ((PRIntervalTime)(now - ad->timein) < ad->duration) ?
  228. PR_TRUE : PR_FALSE;
  229. interval = (ad->period + ad->rate - 1) / ad->rate;
  230. if (!late && (interval > 10))
  231. {
  232. interval &= (now & 0x03) + 1;
  233. PR_WaitCondVar(ad->cv, interval);
  234. }
  235. if (!keepGoing) {
  236. rv = PR_NotifyCondVar(ad->cv);
  237. }
  238. PR_Unlock(ad->ml);
  239. if (rv != PR_SUCCESS) {
  240. failed_already=1;
  241. };
  242. return keepGoing;
  243. } /* AlarmFn2 */
  244. static PRIntervalTime Alarms2(PRUint32 loops)
  245. {
  246. PRStatus rv;
  247. PRAlarm *alarm;
  248. PRIntervalTime overhead, timein = PR_IntervalNow();
  249. AlarmData ad;
  250. PRIntervalTime duration = PR_SecondsToInterval(30);
  251. PRLock *ml = PR_NewLock();
  252. PRCondVar *cv = PR_NewCondVar(ml);
  253. ad.ml = ml;
  254. ad.cv = cv;
  255. ad.rate = 1;
  256. ad.times = loops;
  257. ad.late = ad.times = 0;
  258. ad.duration = duration;
  259. ad.timein = PR_IntervalNow();
  260. ad.period = PR_SecondsToInterval(1);
  261. alarm = PR_CreateAlarm();
  262. (void)PR_SetAlarm(
  263. alarm, ad.period, ad.rate, AlarmFn2, &ad);
  264. overhead = PR_IntervalNow() - timein;
  265. PR_Lock(ml);
  266. while ((PRIntervalTime)(PR_IntervalNow() - ad.timein) < duration) {
  267. PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
  268. }
  269. PR_Unlock(ml);
  270. timein = PR_IntervalNow();
  271. rv = PR_DestroyAlarm(alarm);
  272. if (rv != PR_SUCCESS)
  273. {
  274. if (!debug_mode) {
  275. failed_already=1;
  276. }
  277. else {
  278. printf("***Destroying alarm status: FAIL\n");
  279. }
  280. }
  281. PR_DestroyCondVar(cv);
  282. PR_DestroyLock(ml);
  283. overhead += (PR_IntervalNow() - timein);
  284. return duration + overhead;
  285. } /* Alarms2 */
  286. static PRIntervalTime Alarms3(PRUint32 loops)
  287. {
  288. PRIntn i;
  289. PRStatus rv;
  290. PRAlarm *alarm;
  291. AlarmData ad[3];
  292. PRIntervalTime duration = PR_SecondsToInterval(30);
  293. PRIntervalTime overhead, timein = PR_IntervalNow();
  294. PRLock *ml = PR_NewLock();
  295. PRCondVar *cv = PR_NewCondVar(ml);
  296. for (i = 0; i < 3; ++i)
  297. {
  298. ad[i].ml = ml;
  299. ad[i].cv = cv;
  300. ad[i].rate = 1;
  301. ad[i].times = loops;
  302. ad[i].duration = duration;
  303. ad[i].late = ad[i].times = 0;
  304. ad[i].timein = PR_IntervalNow();
  305. ad[i].period = PR_SecondsToInterval(1);
  306. /* more loops, faster rate => same elapsed time */
  307. ad[i].times = (i + 1) * loops;
  308. ad[i].rate = (i + 1) * 10;
  309. }
  310. alarm = PR_CreateAlarm();
  311. for (i = 0; i < 3; ++i)
  312. {
  313. (void)PR_SetAlarm(
  314. alarm, ad[i].period, ad[i].rate,
  315. AlarmFn2, &ad[i]);
  316. }
  317. overhead = PR_IntervalNow() - timein;
  318. PR_Lock(ml);
  319. for (i = 0; i < 3; ++i)
  320. {
  321. while ((PRIntervalTime)(PR_IntervalNow() - ad[i].timein) < duration) {
  322. PR_WaitCondVar(cv, PR_INTERVAL_NO_TIMEOUT);
  323. }
  324. }
  325. PR_Unlock(ml);
  326. timein = PR_IntervalNow();
  327. if (debug_mode)
  328. printf
  329. ("Alarms3 finished at %u, %u, %u\n",
  330. ad[0].timein, ad[1].timein, ad[2].timein);
  331. rv = PR_DestroyAlarm(alarm);
  332. if (rv != PR_SUCCESS)
  333. {
  334. if (!debug_mode) {
  335. failed_already=1;
  336. }
  337. else {
  338. printf("***Destroying alarm status: FAIL\n");
  339. }
  340. }
  341. PR_DestroyCondVar(cv);
  342. PR_DestroyLock(ml);
  343. overhead += (duration / 3);
  344. overhead += (PR_IntervalNow() - timein);
  345. return overhead;
  346. } /* Alarms3 */
  347. static PRUint32 TimeThis(
  348. const char *msg, PRUint32 (*func)(PRUint32 loops), PRUint32 loops)
  349. {
  350. PRUint32 overhead, usecs;
  351. PRIntervalTime predicted, timein, timeout, ticks;
  352. if (debug_mode) {
  353. printf("Testing %s ...", msg);
  354. }
  355. timein = PR_IntervalNow();
  356. predicted = func(loops);
  357. timeout = PR_IntervalNow();
  358. if (debug_mode) {
  359. printf(" done\n");
  360. }
  361. ticks = timeout - timein;
  362. usecs = PR_IntervalToMicroseconds(ticks);
  363. overhead = PR_IntervalToMicroseconds(predicted);
  364. if(ticks < predicted)
  365. {
  366. if (debug_mode) {
  367. printf("\tFinished in negative time\n");
  368. printf("\tpredicted overhead was %d usecs\n", overhead);
  369. printf("\ttest completed in %d usecs\n\n", usecs);
  370. }
  371. }
  372. else
  373. {
  374. if (debug_mode)
  375. printf(
  376. "\ttotal: %d usecs\n\toverhead: %d usecs\n\tcost: %6.3f usecs\n\n",
  377. usecs, overhead, ((double)(usecs - overhead) / (double)loops));
  378. }
  379. return overhead;
  380. } /* TimeThis */
  381. int prmain(int argc, char** argv)
  382. {
  383. PRUint32 cpu, cpus = 0, loops = 0;
  384. /* The command line argument: -d is used to determine if the test is being run
  385. in debug mode. The regress tool requires only one line output:PASS or FAIL.
  386. All of the printfs associated with this test has been handled with a if (debug_mode)
  387. test.
  388. Usage: test_name [-d]
  389. */
  390. PLOptStatus os;
  391. PLOptState *opt = PL_CreateOptState(argc, argv, "Gdl:c:");
  392. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  393. {
  394. if (PL_OPT_BAD == os) {
  395. continue;
  396. }
  397. switch (opt->option)
  398. {
  399. case 'G': /* GLOBAL threads */
  400. thread_scope = PR_GLOBAL_THREAD;
  401. break;
  402. case 'd': /* debug mode */
  403. debug_mode = 1;
  404. break;
  405. case 'l': /* loop count */
  406. loops = atoi(opt->value);
  407. break;
  408. case 'c': /* concurrency limit */
  409. cpus = atoi(opt->value);
  410. break;
  411. default:
  412. break;
  413. }
  414. }
  415. PL_DestroyOptState(opt);
  416. if (cpus == 0) {
  417. cpus = 1;
  418. }
  419. if (loops == 0) {
  420. loops = 4;
  421. }
  422. if (debug_mode) {
  423. printf("Alarm: Using %d loops\n", loops);
  424. }
  425. if (debug_mode) {
  426. printf("Alarm: Using %d cpu(s)\n", cpus);
  427. }
  428. for (cpu = 1; cpu <= cpus; ++cpu)
  429. {
  430. if (debug_mode) {
  431. printf("\nAlarm: Using %d CPU(s)\n", cpu);
  432. }
  433. PR_SetConcurrency(cpu);
  434. /* some basic time test */
  435. (void)TimeThis("ConditionNotify", ConditionNotify, loops);
  436. (void)TimeThis("ConditionTimeout", ConditionTimeout, loops);
  437. (void)TimeThis("Alarms1", Alarms1, loops);
  438. (void)TimeThis("Alarms2", Alarms2, loops);
  439. (void)TimeThis("Alarms3", Alarms3, loops);
  440. }
  441. return 0;
  442. }
  443. int main(int argc, char** argv)
  444. {
  445. PR_Initialize(prmain, argc, argv, 0);
  446. PR_STDIO_INIT();
  447. if (failed_already) {
  448. return 1;
  449. }
  450. else {
  451. return 0;
  452. }
  453. } /* main */
  454. /* alarmtst.c */