#ifdef __sun
#pragma ident "@(#)trivial.c 1.0 08/17/06 Apple Inc."
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <strings.h>
#include <sys/sysctl.h>
#include "../libmicro.h"
#if 1
# define debug(fmt, args...) (void) fprintf(stderr, fmt "\n" , ##args)
#else
# define debug(fmt, args...)
#endif
#define MAXPROC 2048
#define CHUNK (4<<10)
#define TRIPS 5
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
typedef struct {
int process_size;
double overhead;
int procs;
pid_t* pids;
int **p;
void* data;
} tsd_t;
static int opts = 1;
void doit(int rd, int wr, int process_size);
int create_pipes(int **p, int procs);
int create_daemons(int **p, pid_t *pids, int procs, int process_size);
void initialize_overhead(void* tsd);
void cleanup_overhead(void* tsd);
void benchmark_overhead(void* tsd);
void initialize(void* tsd);
void cleanup(void* tsd);
long bread(void* buf, long nbytes);
#pragma mark *** lmbench routines
void
morefds(void)
{
#ifdef RLIMIT_NOFILE
struct rlimit r;
getrlimit(RLIMIT_NOFILE, &r);
r.rlim_cur = r.rlim_max;
setrlimit(RLIMIT_NOFILE, &r);
#endif
}
void
doit(int rd, int wr, int process_size)
{
int msg;
void* data = NULL;
if (process_size) {
data = malloc(process_size);
if (data) bzero(data, process_size);
}
for ( ;; ) {
if (read(rd, &msg, sizeof(msg)) != sizeof(msg)) {
debug("read/write on pipe");
break;
}
bread(data, process_size);
if (write(wr, &msg, sizeof(msg)) != sizeof(msg)) {
debug("read/write on pipe");
break;
}
}
exit(0);
}
int
sched_ncpus()
{
#ifdef MP_NPROCS
return sysmp(MP_NPROCS);
#elif defined(HAVE_MPCTL)
return mpctl(MPC_GETNUMSPUS_SYS, 0, 0);
#elif defined(_SC_NPROCESSORS_ONLN)
return sysconf(_SC_NPROCESSORS_ONLN);
#elif __APPLE__
char *name="hw.activecpu";
int cpus, retval;
size_t len = 4;
retval=sysctlbyname(name, &cpus, &len, NULL, 0);
debug("cpus = %d retval = %d", cpus, retval);
return cpus;
#endif
return 1;
}
int
reverse_bits(int cpu)
{
int i;
int nbits;
int max = sched_ncpus() - 1;
int cpu_reverse = 0;
for (i = max>>1, nbits = 1; i > 0; i >>= 1, nbits++)
;
for (i = 0; i < nbits; i++) {
if (cpu & (1<<i))
cpu_reverse |= (1<<(nbits-i-1));
}
return cpu_reverse;
}
int
handle_scheduler(int childno, int benchproc, int nbenchprocs)
{
int cpu = 0;
char* sched = getenv("LMBENCH_SCHED");
if (!sched || strcasecmp(sched, "DEFAULT") == 0) {
return 0;
} else if (strcasecmp(sched, "SINGLE") == 0) {
cpu = 0;
} else if (strcasecmp(sched, "BALANCED") == 0) {
cpu = childno;
} else if (strcasecmp(sched, "BALANCED_SPREAD") == 0) {
cpu = reverse_bits(childno);
} else if (strcasecmp(sched, "UNIQUE") == 0) {
cpu = childno * (nbenchprocs + 1) + benchproc;
} else if (strcasecmp(sched, "UNIQUE_SPREAD") == 0) {
cpu = reverse_bits(childno * (nbenchprocs + 1) + benchproc);
}
#if 0 // BLOB
else if (strncasecmp(sched, "CUSTOM ", strlen("CUSTOM ")) == 0) {
cpu = custom(sched + strlen("CUSTOM"), childno);
} else if (strncasecmp(sched, "CUSTOM_UNIQUE ", strlen("CUSTOM_UNIQUE ")) == 0) {
cpu = custom(sched + strlen("CUSTOM_UNIQUE"),
childno * (nbenchprocs + 1) + benchproc);
}
#endif // BLOB
else {
return 0;
}
debug("cpu = %d, sched_ncpus() = %d", cpu, sched_ncpus());
return 0;
}
int
create_daemons(int **p, pid_t *pids, int procs, int process_size)
{
int i, j;
int msg;
handle_scheduler(getpid(), 0, procs-1);
for (i = 1; i < procs; ++i) {
switch (pids[i] = fork()) {
case -1:
return i;
case 0:
handle_scheduler(getpid(), i, procs-1);
for (j = 0; j < procs; ++j) {
if (j != i - 1) close(p[j][0]);
if (j != i) close(p[j][1]);
}
doit(p[i-1][0], p[i][1], process_size);
default:
;
}
}
if (write(p[0][1], &msg, sizeof(msg)) != sizeof(msg) ||
read(p[procs-1][0], &msg, sizeof(msg)) != sizeof(msg)) {
debug("write/read/write on pipe");
exit(1);
}
return procs;
}
int
create_pipes(int **p, int procs)
{
int i;
morefds();
for (i = 0; i < procs; ++i) {
if (pipe(p[i]) == -1) {
return i;
}
}
return procs;
}
void
initialize_overhead(void* cookie)
{
int i;
int procs;
int* p;
tsd_t *pState = (tsd_t *)cookie;
pState->pids = NULL;
pState->p = (int**)malloc(pState->procs * (sizeof(int*) + 2 * sizeof(int)));
p = (int*)&pState->p[pState->procs];
for (i = 0; i < pState->procs; ++i) {
pState->p[i] = p;
p += 2;
}
pState->data = (pState->process_size > 0) ? malloc(pState->process_size) : NULL;
if (pState->data)
bzero(pState->data, pState->process_size);
procs = create_pipes(pState->p, pState->procs);
if (procs < pState->procs) {
debug("procs < pState->procs");
cleanup_overhead(cookie);
exit(1);
}
}
void
cleanup_overhead(void* tsd)
{
int i;
tsd_t *ts = (tsd_t *)tsd;
for (i = 0; i < ts->procs; ++i) {
close(ts->p[i][0]);
close(ts->p[i][1]);
}
free(ts->p);
if (ts->data) free(ts->data);
}
void
cleanup(void* cookie)
{
int i;
tsd_t *pState = (tsd_t *)cookie;
cleanup_overhead(cookie);
for (i = 1; pState->pids && i < pState->procs; ++i) {
if (pState->pids[i] > 0) {
kill(pState->pids[i], SIGKILL);
waitpid(pState->pids[i], NULL, 0);
}
}
if (pState->pids)
free(pState->pids);
pState->pids = NULL;
}
void
benchmark_overhead(void* tsd)
{
tsd_t *ts = (tsd_t *)tsd;
int i = 0;
int msg = 1;
for (i = 0; i < lm_optB; i++) {
if (write(ts->p[i][1], &msg, sizeof(msg)) != sizeof(msg)) {
debug("read/write on pipe");
exit(1);
}
if (read(ts->p[i][0], &msg, sizeof(msg)) != sizeof(msg)) {
debug("read/write on pipe");
exit(1);
}
if (++i == ts->procs) {
i = 0;
}
bread(ts->data, ts->process_size);
}
}
long
bread(void* buf, long nbytes)
{
long sum = 0;
register long *p, *next;
register char *end;
p = (long*)buf;
end = (char*)buf + nbytes;
for (next = p + 128; (void*)next <= (void*)end; p = next, next += 128) {
sum +=
p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7]+
p[8]+p[9]+p[10]+p[11]+p[12]+p[13]+p[14]+
p[15]+p[16]+p[17]+p[18]+p[19]+p[20]+p[21]+
p[22]+p[23]+p[24]+p[25]+p[26]+p[27]+p[28]+
p[29]+p[30]+p[31]+p[32]+p[33]+p[34]+p[35]+
p[36]+p[37]+p[38]+p[39]+p[40]+p[41]+p[42]+
p[43]+p[44]+p[45]+p[46]+p[47]+p[48]+p[49]+
p[50]+p[51]+p[52]+p[53]+p[54]+p[55]+p[56]+
p[57]+p[58]+p[59]+p[60]+p[61]+p[62]+p[63]+
p[64]+p[65]+p[66]+p[67]+p[68]+p[69]+p[70]+
p[71]+p[72]+p[73]+p[74]+p[75]+p[76]+p[77]+
p[78]+p[79]+p[80]+p[81]+p[82]+p[83]+p[84]+
p[85]+p[86]+p[87]+p[88]+p[89]+p[90]+p[91]+
p[92]+p[93]+p[94]+p[95]+p[96]+p[97]+p[98]+
p[99]+p[100]+p[101]+p[102]+p[103]+p[104]+
p[105]+p[106]+p[107]+p[108]+p[109]+p[110]+
p[111]+p[112]+p[113]+p[114]+p[115]+p[116]+
p[117]+p[118]+p[119]+p[120]+p[121]+p[122]+
p[123]+p[124]+p[125]+p[126]+p[127];
}
for (next = p + 16; (void*)next <= (void*)end; p = next, next += 16) {
sum +=
p[0]+p[1]+p[2]+p[3]+p[4]+p[5]+p[6]+p[7]+
p[8]+p[9]+p[10]+p[11]+p[12]+p[13]+p[14]+
p[15];
}
for (next = p + 1; (void*)next <= (void*)end; p = next, next++) {
sum += *p;
}
return sum;
}
#pragma mark *** darbench routines
int
benchmark_initbatch(void *tsd)
{
tsd_t *ts = (tsd_t *)tsd;
int procs;
initialize_overhead(tsd);
ts->pids = (pid_t*)malloc(ts->procs * sizeof(pid_t));
if (ts->pids == NULL)
exit(1);
bzero((void*)ts->pids, ts->procs * sizeof(pid_t));
procs = create_daemons(ts->p, ts->pids,
ts->procs, ts->process_size);
if (procs < ts->procs) {
cleanup(tsd);
exit(1);
}
return (0);
}
int
benchmark_finirun()
{
return (0);
}
int
benchmark_init()
{
(void) sprintf(lm_optstr, "s:");
lm_tsdsize = sizeof (tsd_t);
(void) sprintf(lm_usage,
" [-s kbytes]\n"
" processes [processes ...]\n");
return (0);
}
int
benchmark_fini()
{
return (0);
}
int
benchmark_finibatch(void *tsd)
{
tsd_t *ts = (tsd_t *)tsd;
int i;
cleanup_overhead(tsd);
for (i = 1; ts->pids && i < ts->procs; ++i) {
if (ts->pids[i] > 0) {
kill(ts->pids[i], SIGKILL);
waitpid(ts->pids[i], NULL, 0);
}
}
if (ts->pids)
free(ts->pids);
ts->pids = NULL;
return (0);
}
char *
benchmark_result()
{
static char result = '\0';
return (&result);
}
int
benchmark_finiworker(void *tsd)
{
return (0);
}
int
benchmark_optswitch(int opt, char *optarg)
{
switch (opt) {
case 's':
opts = sizetoint(optarg);
break;
default:
return (-1);
}
return (0);
}
int
benchmark_initworker(void *tsd)
{
tsd_t *ts = (tsd_t *)tsd;
ts->process_size = opts;
return (0);
}
int
benchmark_initrun()
{
return (0);
}
int
benchmark(void *tsd, result_t *res)
{
tsd_t *ts = (tsd_t *)tsd;
int i;
int msg=1;
for (i = 0; i < lm_optB; i++) {
if (write(ts->p[0][1], &msg, sizeof(msg)) !=
sizeof(msg)) {
debug("read/write on pipe");
exit(1);
}
if (read(ts->p[ts->procs-1][0], &msg, sizeof(msg)) != sizeof(msg)) {
debug("read/write on pipe");
exit(1);
}
bread(ts->data, ts->process_size);
}
res->re_count = i;
return (0);
}