/* * Audio component approach cost meter * Copyright (c) 2001 by Abramo Bagnara * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #define MAX_WORKERS 16 #define KEY 0xabce #define PERIOD_SIZE 64 #define RATE 48000 #define CHANNELS 26 #define BUFSIZE (PERIOD_SIZE*CHANNELS) #ifndef STACK_POLLUTION_SIZE #define STACK_POLLUTION_SIZE (4*1024) #endif #ifndef WORKER_POLLUTION_SIZE #define WORKER_POLLUTION_SIZE (32*1024) #endif #ifndef SHARED_POLLUTION_SIZE #define SHARED_POLLUTION_SIZE (64*1024) #endif struct space { float samples[BUFSIZE]; char shared_pollution[SHARED_POLLUTION_SIZE]; }; char worker_pollution[MAX_WORKERS][WORKER_POLLUTION_SIZE]; struct space *area; void proc(unsigned int n) { unsigned int k; float *samples = area->samples; char *wp = worker_pollution[n]; #if STACK_POLLUTION_SIZE > 0 { char stack_pollution[STACK_POLLUTION_SIZE]; memset(stack_pollution, 0xaa, STACK_POLLUTION_SIZE); } #endif #if SHARED_POLLUTION_SIZE > 0 memset(area->shared_pollution, 0xaa, SHARED_POLLUTION_SIZE); #endif #if WORKER_POLLUTION_SIZE > 0 memset(wp, 0xaa, WORKER_POLLUTION_SIZE); #endif for (k = 0; k < BUFSIZE; k++) samples[k]++; } unsigned long long singlethread(unsigned int workers, unsigned int periods) { unsigned long long begin, end; unsigned int k; float *samples; unsigned int p; area = malloc(sizeof(*area)); samples = area->samples; for (k = 0; k < BUFSIZE; k++) samples[k] = 0.0; p = periods; rdtscll(begin); while (p-- > 0) { int n; for (n = 0; n < workers; ++n) { proc(n); } } rdtscll(end); for (k = 0; k < BUFSIZE; k++) assert(samples[k] == periods * workers); free(area); return end - begin; } struct thr { int worker; pthread_t thread; int in, out; } threads[MAX_WORKERS]; void *thread(void *data) { char buf[1]; struct thr *t = data; int err; float *samples = area->samples; char *wp = worker_pollution[t->worker]; while (1) { unsigned int k; err = read(t->in, buf, 1); assert(err == 1); if (!buf[0]) { err = write(t->out, buf, 1); assert(err == 1); break; } #if STACK_POLLUTION_SIZE > 0 { char stack_pollution[STACK_POLLUTION_SIZE]; memset(stack_pollution, 0xaa, STACK_POLLUTION_SIZE); } #endif #if SHARED_POLLUTION_SIZE > 0 memset(area->shared_pollution, 0xaa, SHARED_POLLUTION_SIZE); #endif #if WORKER_POLLUTION_SIZE > 0 memset(wp, 0xaa, WORKER_POLLUTION_SIZE); #endif for (k = 0; k < BUFSIZE; k++) samples[k]++; err = write(t->out, buf, 1); assert(err == 1); } return 0; } unsigned long long multithread(unsigned int workers, unsigned int periods) { unsigned long long begin, end; int err; unsigned int k; char buf[1] = { 1 }; float *samples; unsigned int p; int fds[workers + 1][2]; int in, out; area = malloc(sizeof(*area)); samples = area->samples; for (k = 0; k <= workers; ++k) { err = pipe(fds[k]); assert(err == 0); } out = fds[0][1]; in = fds[workers][0]; for (k = 0; k < workers; ++k) { threads[k].worker = k; threads[k].in = fds[k][0]; threads[k].out = fds[k + 1][1]; err = pthread_create(&threads[k].thread, NULL, thread, &threads[k]); assert(err == 0); } /* Ensure all is started */ err = write(out, buf, 1); assert(err == 1); err = read(in, buf, 1); assert(err == 1); for (k = 0; k < BUFSIZE; k++) samples[k] = 0.0; p = periods; rdtscll(begin); while (p-- > 0) { err = write(out, buf, 1); assert(err == 1); err = read(in, buf, 1); assert(err == 1); } rdtscll(end); buf[0] = 0; err = write(out, buf, 1); assert(err == 1); for (k = 0; k < workers; ++k) { err = pthread_join(threads[k].thread, 0); assert(err == 0); } for (k = 0; k <= workers; ++k) { close(fds[k][0]); close(fds[k][1]); } for (k = 0; k < BUFSIZE; k++) assert(samples[k] == periods * workers); free(area); return end - begin; } struct pro { int worker; pid_t pid; int in, out; } processes[MAX_WORKERS]; void process(struct pro *p) { char buf[1]; int err; float *samples; int shmid = shmget(KEY, sizeof(*area), 0666); char *wp = worker_pollution[p->worker]; assert(shmid >= 0); area = shmat(shmid, NULL, 0); assert(area != (void *) -1); samples = area->samples; while (1) { unsigned int k; err = read(p->in, buf, 1); assert(err == 1); if (!buf[0]) { err = write(p->out, buf, 1); assert(err == 1); break; } #if STACK_POLLUTION_SIZE > 0 { char stack_pollution[STACK_POLLUTION_SIZE]; memset(stack_pollution, 0xaa, STACK_POLLUTION_SIZE); } #endif #if SHARED_POLLUTION_SIZE > 0 memset(area->shared_pollution, 0xaa, SHARED_POLLUTION_SIZE); #endif #if WORKER_POLLUTION_SIZE > 0 memset(wp, 0xaa, WORKER_POLLUTION_SIZE); #endif for (k = 0; k < BUFSIZE; k++) samples[k]++; err = write(p->out, buf, 1); assert(err == 1); } exit(0); } unsigned long long multiprocess(unsigned int workers, unsigned int periods) { unsigned long long begin, end; int err; unsigned int k; char buf[1] = { 1 }; float *samples; int fds[workers + 1][2]; int in, out; int shmid = shmget(KEY, sizeof(*area), IPC_CREAT | 0666); unsigned int p; assert(shmid >= 0); area = shmat(shmid, NULL, 0); assert(area != (void *) -1); samples = area->samples; for (k = 0; k <= workers; ++k) { err = pipe(fds[k]); assert(err == 0); } out = fds[0][1]; in = fds[workers][0]; for (k = 0; k < workers; ++k) { processes[k].worker = k; processes[k].in = fds[k][0]; processes[k].out = fds[k + 1][1]; err = fork(); assert(err >= 0); if (err == 0) process(&processes[k]); processes[k].pid = err; } /* Ensure all is started */ err = write(out, buf, 1); assert(err == 1); err = read(in, buf, 1); assert(err == 1); for (k = 0; k < BUFSIZE; k++) samples[k] = 0.0; p = periods; rdtscll(begin); while (p-- > 0) { err = write(out, buf, 1); assert(err == 1); err = read(in, buf, 1); assert(err == 1); } rdtscll(end); buf[0] = 0; err = write(out, buf, 1); assert(err == 1); for (k = 0; k < workers; ++k) { err = waitpid(processes[k].pid, NULL, 0); assert(err >= 0); } for (k = 0; k <= workers; ++k) { close(fds[k][0]); close(fds[k][1]); } for (k = 0; k < BUFSIZE; k++) assert(samples[k] == periods * workers); err = shmdt(area); assert(err >= 0); err = shmctl(shmid, IPC_RMID, 0); assert(err >= 0); return end - begin; } void setscheduler(void) { struct sched_param sched_param; if (sched_getparam(0, &sched_param) < 0) { printf("Scheduler getparam failed\n"); return; } sched_param.sched_priority = sched_get_priority_max(SCHED_RR); if (!sched_setscheduler(0, SCHED_RR, &sched_param)) { printf("Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority); return; } printf("Scheduler set to Round Robin with priority %i failed\n", sched_param.sched_priority); } #define ST 0 #define MT 1 #define MP 2 /* Usage: ctx workers periods how mhz */ int main(int argc, char **argv) { unsigned long long t; unsigned int workers = atoi(argv[1]); unsigned int periods = atoi(argv[2]); unsigned int how = atoi(argv[3]); double mhz = atof(argv[4]); double c; int k; setscheduler(); for (k = 0; k < 5; ++k) { switch (how) { case ST: t = singlethread(workers, periods); break; case MT: t = multithread(workers, periods); break; case MP: t = multiprocess(workers, periods); break; default: assert(0); break; } c = (double) t / periods; printf("Cycles per period: %f\n", c); printf("%%CPU usage: %f\n", (100 * c / mhz) / (1000000.0 * PERIOD_SIZE / RATE)); } return 0; }