lat_ctx.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * lat_ctx.c - context switch timer
  3. *
  4. * usage: lat_ctx [-s size] #procs [#procs....]
  5. *
  6. * Copyright (c) 1994 Larry McVoy. Distributed under the FSF GPL with
  7. * additional restriction that results may published only if
  8. * (1) the benchmark is unmodified, and
  9. * (2) the version in the sccsid below is included in the report.
  10. * Support for this development by Sun Microsystems is gratefully acknowledged.
  11. */
  12. char *id = "$Id$\n";
  13. #include "bench.h"
  14. #if defined(sgi) && defined(PIN)
  15. #include <sys/sysmp.h>
  16. #include <sys/syssgi.h>
  17. int ncpus;
  18. #endif
  19. #define MAXPROC 2048
  20. #define CHUNK (4<<10)
  21. #define TRIPS 5
  22. #ifndef max
  23. #define max(a, b) ((a) > (b) ? (a) : (b))
  24. #endif
  25. int process_size, *data; /* size & pointer to an array that big */
  26. int pids[MAXPROC];
  27. int p[MAXPROC][2];
  28. double pipe_cost(int p[][2], int procs);
  29. int ctx(int procs, int nprocs);
  30. int sumit(int);
  31. void killem(int procs);
  32. void doit(int p[MAXPROC][2], int rd, int wr);
  33. int create_pipes(int p[][2], int procs);
  34. int create_daemons(int p[][2], int pids[], int procs);
  35. int
  36. main(int ac, char **av)
  37. {
  38. int i, max_procs;
  39. double overhead = 0;
  40. if (ac < 2) {
  41. usage: printf("Usage: %s [-s kbytes] processes [processes ...]\n",
  42. av[0]);
  43. exit(1);
  44. }
  45. /*
  46. * Need 4 byte ints.
  47. */
  48. if (sizeof(int) != 4) {
  49. fprintf(stderr, "Fix sumit() in ctx.c.\n");
  50. exit(1);
  51. }
  52. /*
  53. * If they specified a context size, get it.
  54. */
  55. if (!strcmp(av[1], "-s")) {
  56. if (ac < 4) {
  57. goto usage;
  58. }
  59. process_size = atoi(av[2]) * 1024;
  60. if (process_size > 0) {
  61. data = (int *)calloc(1, max(process_size, CHUNK));
  62. BENCHO(sumit(CHUNK), sumit(0), 0);
  63. overhead = gettime();
  64. overhead /= get_n();
  65. overhead *= process_size;
  66. overhead /= CHUNK;
  67. }
  68. ac -= 2;
  69. av += 2;
  70. }
  71. #if defined(sgi) && defined(PIN)
  72. ncpus = sysmp(MP_NPROCS);
  73. sysmp(MP_MUSTRUN, 0);
  74. #endif
  75. for (max_procs = atoi(av[1]), i = 1; i < ac; ++i) {
  76. int procs = atoi(av[i]);
  77. if (max_procs < procs) max_procs = procs;
  78. }
  79. max_procs = create_pipes(p, max_procs);
  80. overhead += pipe_cost(p, max_procs);
  81. max_procs = create_daemons(p, pids, max_procs);
  82. fprintf(stderr, "\n\"size=%dk ovr=%.2f\n", process_size/1024, overhead);
  83. for (i = 1; i < ac; ++i) {
  84. double time;
  85. int procs = atoi(av[i]);
  86. if (procs > max_procs) continue;
  87. BENCH(ctx(procs, max_procs), 0);
  88. time = usecs_spent();
  89. time /= get_n();
  90. time /= procs;
  91. time /= TRIPS;
  92. time -= overhead;
  93. fprintf(stderr, "%d %.2f\n", procs, time);
  94. }
  95. /*
  96. * Close the pipes and kill the children.
  97. */
  98. killem(max_procs);
  99. for (i = 0; i < max_procs; ++i) {
  100. close(p[i][0]);
  101. close(p[i][1]);
  102. if (i > 0) {
  103. wait(0);
  104. }
  105. }
  106. return (0);
  107. }
  108. int
  109. ctx(int procs, int nprocs)
  110. {
  111. int msg;
  112. int i;
  113. int sum;
  114. /*
  115. * Main process - all others should be ready to roll, time the
  116. * loop.
  117. */
  118. for (i = 0; i < TRIPS; ++i) {
  119. if (write(p[nprocs - procs][1], &msg, sizeof(msg)) !=
  120. sizeof(msg)) {
  121. if (errno) perror("read/write on pipe");
  122. exit(1);
  123. }
  124. if (read(p[nprocs-1][0], &msg, sizeof(msg)) != sizeof(msg)) {
  125. if (errno) perror("read/write on pipe");
  126. exit(1);
  127. }
  128. sum = sumit(process_size);
  129. }
  130. return (sum);
  131. }
  132. void
  133. killem(int procs)
  134. {
  135. int i;
  136. for (i = 1; i < procs; ++i) {
  137. if (pids[i] > 0) {
  138. kill(pids[i], SIGTERM);
  139. }
  140. }
  141. }
  142. void
  143. doit(int p[][2], int rd, int wr)
  144. {
  145. int msg, sum = 0 /* lint */;
  146. signal(SIGTERM, SIG_DFL);
  147. if (data) bzero((void*)data, process_size);
  148. for ( ;; ) {
  149. if (read(p[rd][0], &msg, sizeof(msg)) != sizeof(msg)) {
  150. if (errno) perror("read/write on pipe");
  151. break;
  152. }
  153. sum = sumit(process_size);
  154. if (write(p[wr][1], &msg, sizeof(msg)) != sizeof(msg)) {
  155. if (errno) perror("read/write on pipe");
  156. break;
  157. }
  158. }
  159. use_int(sum);
  160. exit(1);
  161. }
  162. int
  163. doit_cost(int p[][2], int procs)
  164. {
  165. static int k;
  166. int msg = 1;
  167. int i;
  168. for (i = 0; i < TRIPS; ++i) {
  169. if (write(p[k][1], &msg, sizeof(msg)) != sizeof(msg)) {
  170. if (errno) perror("read/write on pipe");
  171. exit(1);
  172. }
  173. if (read(p[k][0], &msg, sizeof(msg)) != sizeof(msg)) {
  174. if (errno) perror("read/write on pipe");
  175. exit(1);
  176. }
  177. if (++k == procs) {
  178. k = 0;
  179. }
  180. }
  181. return (msg);
  182. }
  183. /*
  184. * The cost returned is the cost of going through one pipe once in usecs.
  185. * No memory costs are included here, this is different than lmbench1.
  186. */
  187. double
  188. pipe_cost(int p[][2], int procs)
  189. {
  190. double result;
  191. /*
  192. * Measure the overhead of passing a byte around the ring.
  193. */
  194. BENCH(doit_cost(p, procs), 0);
  195. result = usecs_spent();
  196. result /= get_n();
  197. result /= TRIPS;
  198. return result;
  199. }
  200. int
  201. create_daemons(int p[][2], int pids[], int procs)
  202. {
  203. int i, j;
  204. int msg;
  205. /*
  206. * Use the pipes as a ring, and fork off a bunch of processes
  207. * to pass the byte through their part of the ring.
  208. *
  209. * Do the sum in each process and get that time before moving on.
  210. */
  211. signal(SIGTERM, SIG_IGN);
  212. bzero(pids, procs * sizeof(pid_t));
  213. for (i = 1; i < procs; ++i) {
  214. switch (pids[i] = fork()) {
  215. case -1: /* could not fork, out of processes? */
  216. procs = i;
  217. break;
  218. case 0: /* child */
  219. #if defined(sgi) && defined(PIN)
  220. sysmp(MP_MUSTRUN, i % ncpus);
  221. #endif
  222. for (j = 0; j < procs; ++j) {
  223. if (j != i-1) close(p[j][0]);
  224. if (j != i) close(p[j][1]);
  225. }
  226. doit(p, i-1, i);
  227. /* NOTREACHED */
  228. default: /* parent */
  229. ;
  230. }
  231. }
  232. /*
  233. * Go once around the loop to make sure that everyone is ready and
  234. * to get the token in the pipeline.
  235. */
  236. if (write(p[0][1], &msg, sizeof(msg)) != sizeof(msg) ||
  237. read(p[procs-1][0], &msg, sizeof(msg)) != sizeof(msg)) {
  238. if (errno) perror("write/read/write on pipe");
  239. exit(1);
  240. }
  241. if (data) bzero((void*)data, process_size);
  242. return procs;
  243. }
  244. int
  245. create_pipes(int p[][2], int procs)
  246. {
  247. int i;
  248. /*
  249. * Get a bunch of pipes.
  250. */
  251. morefds();
  252. for (i = 0; i < procs; ++i) {
  253. if (pipe(p[i]) == -1) {
  254. return i;
  255. }
  256. }
  257. return procs;
  258. }
  259. /*
  260. * Bring howmuch data into the cache, assuming that the smallest cache
  261. * line is 16 bytes.
  262. */
  263. int
  264. sumit(int howmuch)
  265. {
  266. int done, sum = 0;
  267. register int *d = data;
  268. #if 0
  269. #define A sum+=d[0]+d[4]+d[8]+d[12]+d[16]+d[20]+d[24]+d[28]+\
  270. d[32]+d[36]+d[40]+d[44]+d[48]+d[52]+d[56]+d[60]+\
  271. d[64]+d[68]+d[72]+d[76]+d[80]+d[84]+d[88]+d[92]+\
  272. d[96]+d[100]+d[104]+d[108]+d[112]+d[116]+d[120]+d[124];\
  273. d+=128;
  274. #define TWOKB A A A A
  275. #else
  276. #define A sum+=d[0]+d[1]+d[2]+d[3]+d[4]+d[5]+d[6]+d[7]+d[8]+d[9]+\
  277. d[10]+d[11]+d[12]+d[13]+d[14]+d[15]+d[16]+d[17]+d[18]+d[19]+\
  278. d[20]+d[21]+d[22]+d[23]+d[24]+d[25]+d[26]+d[27]+d[28]+d[29]+\
  279. d[30]+d[31]+d[32]+d[33]+d[34]+d[35]+d[36]+d[37]+d[38]+d[39]+\
  280. d[40]+d[41]+d[42]+d[43]+d[44]+d[45]+d[46]+d[47]+d[48]+d[49]+\
  281. d[50]+d[51]+d[52]+d[53]+d[54]+d[55]+d[56]+d[57]+d[58]+d[59]+\
  282. d[60]+d[61]+d[62]+d[63]+d[64]+d[65]+d[66]+d[67]+d[68]+d[69]+\
  283. d[70]+d[71]+d[72]+d[73]+d[74]+d[75]+d[76]+d[77]+d[78]+d[79]+\
  284. d[80]+d[81]+d[82]+d[83]+d[84]+d[85]+d[86]+d[87]+d[88]+d[89]+\
  285. d[90]+d[91]+d[92]+d[93]+d[94]+d[95]+d[96]+d[97]+d[98]+d[99]+\
  286. d[100]+d[101]+d[102]+d[103]+d[104]+\
  287. d[105]+d[106]+d[107]+d[108]+d[109]+\
  288. d[110]+d[111]+d[112]+d[113]+d[114]+\
  289. d[115]+d[116]+d[117]+d[118]+d[119]+\
  290. d[120]+d[121]+d[122]+d[123]+d[124]+d[125]+d[126]+d[127];\
  291. d+=128; /* ints; bytes == 512 */
  292. #define TWOKB A A A A
  293. #endif
  294. for (done = 0; done < howmuch; done += 2048) {
  295. TWOKB
  296. }
  297. return (sum);
  298. }