switch.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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. ** File: switch.c
  7. ** Description: trying to time context switches
  8. */
  9. #include "prinit.h"
  10. #include "prcvar.h"
  11. #include "prmem.h"
  12. #include "prinrval.h"
  13. #include "prlock.h"
  14. #include "prlog.h"
  15. #include "prthread.h"
  16. #include "prprf.h"
  17. #include "plerror.h"
  18. #include "plgetopt.h"
  19. #include "private/pprio.h"
  20. #include <stdlib.h>
  21. #define INNER_LOOPS 100
  22. #define DEFAULT_LOOPS 100
  23. #define DEFAULT_THREADS 10
  24. static PRFileDesc *debug_out = NULL;
  25. static PRBool debug_mode = PR_FALSE, verbosity = PR_FALSE, failed = PR_FALSE;
  26. typedef struct Shared
  27. {
  28. PRLock *ml;
  29. PRCondVar *cv;
  30. PRBool twiddle;
  31. PRThread *thread;
  32. struct Shared *next;
  33. } Shared;
  34. static void Help(void)
  35. {
  36. debug_out = PR_STDOUT;
  37. PR_fprintf(
  38. debug_out, "Usage: >./switch [-c n] [-t n] [-d] [-v] [-G] [-C n]\n");
  39. PR_fprintf(
  40. debug_out, "-c n\tloops at thread level (default: %d)\n", DEFAULT_LOOPS);
  41. PR_fprintf(
  42. debug_out, "-t n\tnumber of threads (default: %d)\n", DEFAULT_THREADS);
  43. PR_fprintf(debug_out, "-d\tturn on debugging output (default: FALSE)\n");
  44. PR_fprintf(debug_out, "-v\tturn on verbose output (default: FALSE)\n");
  45. PR_fprintf(debug_out, "-G\tglobal threads only (default: FALSE)\n");
  46. PR_fprintf(debug_out, "-C n\tconcurrency setting (default: 1)\n");
  47. } /* Help */
  48. static void PR_CALLBACK Notified(void *arg)
  49. {
  50. Shared *shared = (Shared*)arg;
  51. PRStatus status = PR_SUCCESS;
  52. while (PR_SUCCESS == status)
  53. {
  54. PR_Lock(shared->ml);
  55. while (shared->twiddle && (PR_SUCCESS == status)) {
  56. status = PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
  57. }
  58. if (verbosity) {
  59. PR_fprintf(debug_out, "+");
  60. }
  61. shared->twiddle = PR_TRUE;
  62. shared->next->twiddle = PR_FALSE;
  63. PR_NotifyCondVar(shared->next->cv);
  64. PR_Unlock(shared->ml);
  65. }
  66. } /* Notified */
  67. static Shared home;
  68. PRIntn PR_CALLBACK Switch(PRIntn argc, char **argv)
  69. {
  70. PLOptStatus os;
  71. PRStatus status;
  72. PRBool help = PR_FALSE;
  73. PRUintn concurrency = 1;
  74. Shared *shared, *link;
  75. PRIntervalTime timein, timeout;
  76. PRThreadScope thread_scope = PR_LOCAL_THREAD;
  77. PRUintn thread_count, inner_count, loop_count, average;
  78. PRUintn thread_limit = DEFAULT_THREADS, loop_limit = DEFAULT_LOOPS;
  79. PLOptState *opt = PL_CreateOptState(argc, argv, "hdvc:t:C:G");
  80. while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
  81. {
  82. if (PL_OPT_BAD == os) {
  83. continue;
  84. }
  85. switch (opt->option)
  86. {
  87. case 'v': /* verbose mode */
  88. verbosity = PR_TRUE;
  89. case 'd': /* debug mode */
  90. debug_mode = PR_TRUE;
  91. break;
  92. case 'c': /* loop counter */
  93. loop_limit = atoi(opt->value);
  94. break;
  95. case 't': /* thread limit */
  96. thread_limit = atoi(opt->value);
  97. break;
  98. case 'C': /* Concurrency limit */
  99. concurrency = atoi(opt->value);
  100. break;
  101. case 'G': /* global threads only */
  102. thread_scope = PR_GLOBAL_THREAD;
  103. break;
  104. case 'h': /* help message */
  105. Help();
  106. help = PR_TRUE;
  107. break;
  108. default:
  109. break;
  110. }
  111. }
  112. PL_DestroyOptState(opt);
  113. if (help) {
  114. return -1;
  115. }
  116. if (PR_TRUE == debug_mode)
  117. {
  118. debug_out = PR_STDOUT;
  119. PR_fprintf(debug_out, "Test parameters\n");
  120. PR_fprintf(debug_out, "\tThreads involved: %d\n", thread_limit);
  121. PR_fprintf(debug_out, "\tIteration limit: %d\n", loop_limit);
  122. PR_fprintf(debug_out, "\tConcurrency: %d\n", concurrency);
  123. PR_fprintf(
  124. debug_out, "\tThread type: %s\n",
  125. (PR_GLOBAL_THREAD == thread_scope) ? "GLOBAL" : "LOCAL");
  126. }
  127. PR_SetConcurrency(concurrency);
  128. link = &home;
  129. home.ml = PR_NewLock();
  130. home.cv = PR_NewCondVar(home.ml);
  131. home.twiddle = PR_FALSE;
  132. home.next = NULL;
  133. timeout = 0;
  134. for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
  135. {
  136. shared = PR_NEWZAP(Shared);
  137. shared->ml = home.ml;
  138. shared->cv = PR_NewCondVar(home.ml);
  139. shared->twiddle = PR_TRUE;
  140. shared->next = link;
  141. link = shared;
  142. shared->thread = PR_CreateThread(
  143. PR_USER_THREAD, Notified, shared,
  144. PR_PRIORITY_HIGH, thread_scope,
  145. PR_JOINABLE_THREAD, 0);
  146. PR_ASSERT(shared->thread != NULL);
  147. if (NULL == shared->thread) {
  148. failed = PR_TRUE;
  149. }
  150. }
  151. for (loop_count = 1; loop_count <= loop_limit; ++loop_count)
  152. {
  153. timein = PR_IntervalNow();
  154. for (inner_count = 0; inner_count < INNER_LOOPS; ++inner_count)
  155. {
  156. PR_Lock(home.ml);
  157. home.twiddle = PR_TRUE;
  158. shared->twiddle = PR_FALSE;
  159. PR_NotifyCondVar(shared->cv);
  160. while (home.twiddle)
  161. {
  162. status = PR_WaitCondVar(home.cv, PR_INTERVAL_NO_TIMEOUT);
  163. if (PR_FAILURE == status) {
  164. failed = PR_TRUE;
  165. }
  166. }
  167. PR_Unlock(home.ml);
  168. }
  169. timeout += (PR_IntervalNow() - timein);
  170. }
  171. if (debug_mode)
  172. {
  173. average = PR_IntervalToMicroseconds(timeout)
  174. / (INNER_LOOPS * loop_limit * thread_count);
  175. PR_fprintf(
  176. debug_out, "Average switch times %d usecs for %d threads\n",
  177. average, thread_limit);
  178. }
  179. link = shared;
  180. for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
  181. {
  182. if (&home == link) {
  183. break;
  184. }
  185. status = PR_Interrupt(link->thread);
  186. if (PR_SUCCESS != status)
  187. {
  188. failed = PR_TRUE;
  189. if (debug_mode) {
  190. PL_FPrintError(debug_out, "Failed to interrupt");
  191. }
  192. }
  193. link = link->next;
  194. }
  195. for (thread_count = 1; thread_count <= thread_limit; ++thread_count)
  196. {
  197. link = shared->next;
  198. status = PR_JoinThread(shared->thread);
  199. if (PR_SUCCESS != status)
  200. {
  201. failed = PR_TRUE;
  202. if (debug_mode) {
  203. PL_FPrintError(debug_out, "Failed to join");
  204. }
  205. }
  206. PR_DestroyCondVar(shared->cv);
  207. PR_DELETE(shared);
  208. if (&home == link) {
  209. break;
  210. }
  211. shared = link;
  212. }
  213. PR_DestroyCondVar(home.cv);
  214. PR_DestroyLock(home.ml);
  215. PR_fprintf(PR_STDOUT, ((failed) ? "FAILED\n" : "PASSED\n"));
  216. return ((failed) ? 1 : 0);
  217. } /* Switch */
  218. int main(int argc, char **argv)
  219. {
  220. PRIntn result;
  221. PR_STDIO_INIT();
  222. result = PR_Initialize(Switch, argc, argv, 0);
  223. return result;
  224. } /* main */
  225. /* switch.c */