]>
git.saurik.com Git - apple/xnu.git/blob - tools/tests/libMicro/apple/lmbench_lat_ctx.c
2cbe790c275c86be46eb08fd047e5f69c0acdbd3
2 * Copyright (c) 2006 Apple Inc. All Rights Reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
39 * benchmark_initworker
45 * benchmark_finibatch, etc.
46 * benchmark_finiworker
58 #pragma ident "@(#)trivial.c 1.0 08/17/06 Apple Inc."
70 #include <sys/sysctl.h>
71 #include "../libmicro.h"
74 # define debug(fmt, args...) (void) fprintf(stderr, fmt "\n" , ##args)
76 # define debug(fmt, args...)
84 #define max(a, b) ((a) > (b) ? (a) : (b))
89 * Your state variables should live in the tsd_t struct below
102 void doit(int rd
, int wr
, int process_size
);
103 int create_pipes(int **p
, int procs
);
104 int create_daemons(int **p
, pid_t
*pids
, int procs
, int process_size
);
105 void initialize_overhead(void* tsd
);
106 void cleanup_overhead(void* tsd
);
107 void benchmark_overhead(void* tsd
);
108 void initialize(void* tsd
);
109 void cleanup(void* tsd
);
110 long bread(void* buf
, long nbytes
);
113 #pragma mark *** lmbench routines
116 * lmbench routines, etc. brought over for this benchmark
125 getrlimit(RLIMIT_NOFILE
, &r
);
126 r
.rlim_cur
= r
.rlim_max
;
127 setrlimit(RLIMIT_NOFILE
, &r
);
132 doit(int rd
, int wr
, int process_size
)
138 data
= malloc(process_size
);
139 if (data
) bzero(data
, process_size
);
142 if (read(rd
, &msg
, sizeof(msg
)) != sizeof(msg
)) {
143 debug("read/write on pipe");
146 bread(data
, process_size
);
147 if (write(wr
, &msg
, sizeof(msg
)) != sizeof(msg
)) {
148 debug("read/write on pipe");
156 * Return the number of processors in this host
162 /* SGI IRIX interface */
163 return sysmp(MP_NPROCS
);
164 #elif defined(HAVE_MPCTL)
165 /* HP-UX interface */
166 return mpctl(MPC_GETNUMSPUS_SYS
, 0, 0);
167 #elif defined(_SC_NPROCESSORS_ONLN)
168 /* AIX, Solaris, and Linux interface */
169 return sysconf(_SC_NPROCESSORS_ONLN
);
171 char *name
="hw.activecpu";
174 retval
=sysctlbyname(name
, &cpus
, &len
, NULL
, 0);
175 /* Check retval here */
176 debug("cpus = %d retval = %d", cpus
, retval
);
183 * Use to get sequentially created processes "far" away from
184 * each other in an SMP.
186 * XXX: probably doesn't work for NCPUS not a power of two.
189 reverse_bits(int cpu
)
193 int max
= sched_ncpus() - 1;
196 for (i
= max
>>1, nbits
= 1; i
> 0; i
>>= 1, nbits
++)
198 /* now reverse the bits */
199 for (i
= 0; i
< nbits
; i
++) {
201 cpu_reverse
|= (1<<(nbits
-i
-1));
208 * The interface used by benchmp.
210 * childno is the "logical" child id number.
211 * In range [0, ..., parallel-1].
212 * benchproc is the "logical" id within the benchmark process. The
213 * benchmp-created process is logical ID zero, child processes
214 * created by the benchmark range from [1, ..., nbenchprocs].
215 * nbenchprocs is the number of child processes that each benchmark
216 * process will create. Most benchmarks will leave this zero,
217 * but some such as the pipe() benchmarks will not.
220 handle_scheduler(int childno
, int benchproc
, int nbenchprocs
)
223 char* sched
= getenv("LMBENCH_SCHED");
225 if (!sched
|| strcasecmp(sched
, "DEFAULT") == 0) {
226 /* do nothing. Allow scheduler to control placement */
228 } else if (strcasecmp(sched
, "SINGLE") == 0) {
229 /* assign all processes to CPU 0 */
231 } else if (strcasecmp(sched
, "BALANCED") == 0) {
232 /* assign each benchmark process to its own processor,
233 * but child processes will share the CPU with the
237 } else if (strcasecmp(sched
, "BALANCED_SPREAD") == 0) {
239 * assign each benchmark process to its own processor,
240 * logically as far away from neighboring IDs as
241 * possible. This can help identify bus contention
242 * issues in SMPs with hierarchical busses or NUMA
245 cpu
= reverse_bits(childno
);
246 } else if (strcasecmp(sched
, "UNIQUE") == 0) {
248 * assign each benchmark process and each child process
249 * to its own processor.
251 cpu
= childno
* (nbenchprocs
+ 1) + benchproc
;
252 } else if (strcasecmp(sched
, "UNIQUE_SPREAD") == 0) {
254 * assign each benchmark process and each child process
255 * to its own processor, logically as far away from
256 * neighboring IDs as possible. This can help identify
257 * bus contention issues in SMPs with hierarchical busses
260 cpu
= reverse_bits(childno
* (nbenchprocs
+ 1) + benchproc
);
263 else if (strncasecmp(sched
, "CUSTOM ", strlen("CUSTOM ")) == 0) {
264 cpu
= custom(sched
+ strlen("CUSTOM"), childno
);
265 } else if (strncasecmp(sched
, "CUSTOM_UNIQUE ", strlen("CUSTOM_UNIQUE ")) == 0) {
266 cpu
= custom(sched
+ strlen("CUSTOM_UNIQUE"),
267 childno
* (nbenchprocs
+ 1) + benchproc
);
271 /* default action: do nothing */
274 debug("cpu = %d, sched_ncpus() = %d", cpu
, sched_ncpus());
276 // return sched_pin(cpu % sched_ncpus());
280 create_daemons(int **p
, pid_t
*pids
, int procs
, int process_size
)
286 * Use the pipes as a ring, and fork off a bunch of processes
287 * to pass the byte through their part of the ring.
289 * Do the sum in each process and get that time before moving on.
291 handle_scheduler(getpid(), 0, procs
-1);
292 for (i
= 1; i
< procs
; ++i
) {
293 switch (pids
[i
] = fork()) {
294 case -1: /* could not fork, out of processes? */
298 handle_scheduler(getpid(), i
, procs
-1);
299 for (j
= 0; j
< procs
; ++j
) {
300 if (j
!= i
- 1) close(p
[j
][0]);
301 if (j
!= i
) close(p
[j
][1]);
303 doit(p
[i
-1][0], p
[i
][1], process_size
);
306 default: /* parent */
312 * Go once around the loop to make sure that everyone is ready and
313 * to get the token in the pipeline.
315 if (write(p
[0][1], &msg
, sizeof(msg
)) != sizeof(msg
) ||
316 read(p
[procs
-1][0], &msg
, sizeof(msg
)) != sizeof(msg
)) {
317 debug("write/read/write on pipe");
324 create_pipes(int **p
, int procs
)
328 * Get a bunch of pipes.
331 for (i
= 0; i
< procs
; ++i
) {
332 if (pipe(p
[i
]) == -1) {
340 initialize_overhead(void* cookie
)
345 tsd_t
*pState
= (tsd_t
*)cookie
;
348 pState
->p
= (int**)malloc(pState
->procs
* (sizeof(int*) + 2 * sizeof(int)));
349 p
= (int*)&pState
->p
[pState
->procs
];
350 for (i
= 0; i
< pState
->procs
; ++i
) {
355 pState
->data
= (pState
->process_size
> 0) ? malloc(pState
->process_size
) : NULL
;
357 bzero(pState
->data
, pState
->process_size
);
359 procs
= create_pipes(pState
->p
, pState
->procs
);
360 if (procs
< pState
->procs
) {
361 debug("procs < pState->procs");
362 cleanup_overhead(cookie
);
368 cleanup_overhead(void* tsd
)
371 tsd_t
*ts
= (tsd_t
*)tsd
;
373 for (i
= 0; i
< ts
->procs
; ++i
) {
379 if (ts
->data
) free(ts
->data
);
383 cleanup(void* cookie
)
386 tsd_t
*pState
= (tsd_t
*)cookie
;
390 * Close the pipes and kill the children.
392 cleanup_overhead(cookie
);
393 for (i
= 1; pState
->pids
&& i
< pState
->procs
; ++i
) {
394 if (pState
->pids
[i
] > 0) {
395 kill(pState
->pids
[i
], SIGKILL
);
396 waitpid(pState
->pids
[i
], NULL
, 0);
405 benchmark_overhead(void* tsd
)
407 tsd_t
*ts
= (tsd_t
*)tsd
;
411 for (i
= 0; i
< lm_optB
; i
++) {
412 if (write(ts
->p
[i
][1], &msg
, sizeof(msg
)) != sizeof(msg
)) {
413 debug("read/write on pipe");
416 if (read(ts
->p
[i
][0], &msg
, sizeof(msg
)) != sizeof(msg
)) {
417 debug("read/write on pipe");
420 if (++i
== ts
->procs
) {
423 bread(ts
->data
, ts
->process_size
);
427 /* analogous to bzero, bcopy, etc., except that it just reads
428 * data into the processor
431 bread(void* buf
, long nbytes
)
434 register long *p
, *next
;
438 end
= (char*)buf
+ nbytes
;
439 for (next
= p
+ 128; (void*)next
<= (void*)end
; p
= next
, next
+= 128) {
441 p
[0]+p
[1]+p
[2]+p
[3]+p
[4]+p
[5]+p
[6]+p
[7]+
442 p
[8]+p
[9]+p
[10]+p
[11]+p
[12]+p
[13]+p
[14]+
443 p
[15]+p
[16]+p
[17]+p
[18]+p
[19]+p
[20]+p
[21]+
444 p
[22]+p
[23]+p
[24]+p
[25]+p
[26]+p
[27]+p
[28]+
445 p
[29]+p
[30]+p
[31]+p
[32]+p
[33]+p
[34]+p
[35]+
446 p
[36]+p
[37]+p
[38]+p
[39]+p
[40]+p
[41]+p
[42]+
447 p
[43]+p
[44]+p
[45]+p
[46]+p
[47]+p
[48]+p
[49]+
448 p
[50]+p
[51]+p
[52]+p
[53]+p
[54]+p
[55]+p
[56]+
449 p
[57]+p
[58]+p
[59]+p
[60]+p
[61]+p
[62]+p
[63]+
450 p
[64]+p
[65]+p
[66]+p
[67]+p
[68]+p
[69]+p
[70]+
451 p
[71]+p
[72]+p
[73]+p
[74]+p
[75]+p
[76]+p
[77]+
452 p
[78]+p
[79]+p
[80]+p
[81]+p
[82]+p
[83]+p
[84]+
453 p
[85]+p
[86]+p
[87]+p
[88]+p
[89]+p
[90]+p
[91]+
454 p
[92]+p
[93]+p
[94]+p
[95]+p
[96]+p
[97]+p
[98]+
455 p
[99]+p
[100]+p
[101]+p
[102]+p
[103]+p
[104]+
456 p
[105]+p
[106]+p
[107]+p
[108]+p
[109]+p
[110]+
457 p
[111]+p
[112]+p
[113]+p
[114]+p
[115]+p
[116]+
458 p
[117]+p
[118]+p
[119]+p
[120]+p
[121]+p
[122]+
459 p
[123]+p
[124]+p
[125]+p
[126]+p
[127];
461 for (next
= p
+ 16; (void*)next
<= (void*)end
; p
= next
, next
+= 16) {
463 p
[0]+p
[1]+p
[2]+p
[3]+p
[4]+p
[5]+p
[6]+p
[7]+
464 p
[8]+p
[9]+p
[10]+p
[11]+p
[12]+p
[13]+p
[14]+
467 for (next
= p
+ 1; (void*)next
<= (void*)end
; p
= next
, next
++) {
473 #pragma mark *** darbench routines
478 benchmark_initbatch(void *tsd
)
481 * initialize your state variables here second
483 tsd_t
*ts
= (tsd_t
*)tsd
;
486 initialize_overhead(tsd
);
488 ts
->pids
= (pid_t
*)malloc(ts
->procs
* sizeof(pid_t
));
489 if (ts
->pids
== NULL
)
491 bzero((void*)ts
->pids
, ts
->procs
* sizeof(pid_t
));
492 procs
= create_daemons(ts
->p
, ts
->pids
,
493 ts
->procs
, ts
->process_size
);
494 if (procs
< ts
->procs
) {
511 * the lm_optstr must be defined here or no options for you
513 * ...and the framework will throw an error
516 (void) sprintf(lm_optstr
, "s:");
518 * working hypothesis:
520 * tsd_t is the struct that we can pass around our
523 * lm_tsdsize will allocate the space we need for this
524 * structure throughout the rest of the framework
526 lm_tsdsize
= sizeof (tsd_t
);
528 (void) sprintf(lm_usage
,
530 " processes [processes ...]\n");
542 benchmark_finibatch(void *tsd
)
544 tsd_t
*ts
= (tsd_t
*)tsd
;
548 * Close the pipes and kill the children.
550 cleanup_overhead(tsd
);
551 for (i
= 1; ts
->pids
&& i
< ts
->procs
; ++i
) {
552 if (ts
->pids
[i
] > 0) {
553 kill(ts
->pids
[i
], SIGKILL
);
554 waitpid(ts
->pids
[i
], NULL
, 0);
566 static char result
= '\0';
571 benchmark_finiworker(void *tsd
)
577 benchmark_optswitch(int opt
, char *optarg
)
582 opts
= sizetoint(optarg
);
591 benchmark_initworker(void *tsd
)
593 tsd_t
*ts
= (tsd_t
*)tsd
;
595 ts
->process_size
= opts
;
607 benchmark(void *tsd
, result_t
*res
)
610 * initialize your state variables here last
612 * and realize that you are paying for your initialization here
613 * and it is really a bad idea
615 tsd_t
*ts
= (tsd_t
*)tsd
;
619 for (i
= 0; i
< lm_optB
; i
++) {
620 if (write(ts
->p
[0][1], &msg
, sizeof(msg
)) !=
622 debug("read/write on pipe");
625 if (read(ts
->p
[ts
->procs
-1][0], &msg
, sizeof(msg
)) != sizeof(msg
)) {
626 debug("read/write on pipe");
629 bread(ts
->data
, ts
->process_size
);