186d7f5d3SJohn Marino /*******************************************
286d7f5d3SJohn Marino *
386d7f5d3SJohn Marino * Interbench - Interactivity benchmark
486d7f5d3SJohn Marino *
586d7f5d3SJohn Marino * Author: Con Kolivas <kernel@kolivas.org>
686d7f5d3SJohn Marino *
786d7f5d3SJohn Marino * This program is free software; you can redistribute it and/or modify
886d7f5d3SJohn Marino * it under the terms of the GNU General Public License as published by
986d7f5d3SJohn Marino * the Free Software Foundation; either version 2 of the License, or
1086d7f5d3SJohn Marino * (at your option) any later version.
1186d7f5d3SJohn Marino *
1286d7f5d3SJohn Marino * This program is distributed in the hope that it will be useful,
1386d7f5d3SJohn Marino * but WITHOUT ANY WARRANTY; without even the implied warranty of
1486d7f5d3SJohn Marino * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1586d7f5d3SJohn Marino * GNU General Public License for more details.
1686d7f5d3SJohn Marino *
1786d7f5d3SJohn Marino * You should have received a copy of the GNU General Public License
1886d7f5d3SJohn Marino * along with this program; if not, write to the Free Software
1986d7f5d3SJohn Marino * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2086d7f5d3SJohn Marino *
2186d7f5d3SJohn Marino *******************************************/
2286d7f5d3SJohn Marino
2386d7f5d3SJohn Marino #define _GNU_SOURCE
2486d7f5d3SJohn Marino #define _FILE_OFFSET_BITS 64 /* Large file support */
2586d7f5d3SJohn Marino #define INTERBENCH_VERSION "0.30"
2686d7f5d3SJohn Marino
2786d7f5d3SJohn Marino #include <stdio.h>
2886d7f5d3SJohn Marino #include <stdlib.h>
2986d7f5d3SJohn Marino #include <stdarg.h>
3086d7f5d3SJohn Marino #include <strings.h>
3186d7f5d3SJohn Marino #include <string.h>
3286d7f5d3SJohn Marino #include <unistd.h>
3386d7f5d3SJohn Marino #include <fcntl.h>
3486d7f5d3SJohn Marino #include <sched.h>
3586d7f5d3SJohn Marino #include <time.h>
3686d7f5d3SJohn Marino #include <errno.h>
3786d7f5d3SJohn Marino #include <semaphore.h>
3886d7f5d3SJohn Marino #include <pthread.h>
3986d7f5d3SJohn Marino #include <math.h>
4086d7f5d3SJohn Marino #include <fenv.h>
4186d7f5d3SJohn Marino #include <signal.h>
4286d7f5d3SJohn Marino #include <sys/utsname.h>
4386d7f5d3SJohn Marino #include <sys/time.h>
4486d7f5d3SJohn Marino #include <sys/resource.h>
4586d7f5d3SJohn Marino #include <sys/types.h>
4686d7f5d3SJohn Marino #include <sys/mman.h>
4786d7f5d3SJohn Marino #include <sys/wait.h>
4886d7f5d3SJohn Marino #include <sys/stat.h>
4986d7f5d3SJohn Marino #include <sys/sysctl.h>
5086d7f5d3SJohn Marino #include <sys/vmmeter.h>
5186d7f5d3SJohn Marino #include "interbench.h"
5286d7f5d3SJohn Marino
5386d7f5d3SJohn Marino #define MAX_UNAME_LENGTH 100
5486d7f5d3SJohn Marino #define MAX_LOG_LENGTH ((MAX_UNAME_LENGTH) + 4)
5586d7f5d3SJohn Marino #define MIN_BLK_SIZE 1024
5686d7f5d3SJohn Marino #define DEFAULT_RESERVE 64
5786d7f5d3SJohn Marino #define MB (1024 * 1024) /* 2^20 bytes */
5886d7f5d3SJohn Marino #define KB 1024
5986d7f5d3SJohn Marino #define MAX_MEM_IN_MB (1024 * 64) /* 64 GB */
6086d7f5d3SJohn Marino
6186d7f5d3SJohn Marino struct user_data {
6286d7f5d3SJohn Marino unsigned long loops_per_ms;
6386d7f5d3SJohn Marino unsigned long ram, swap;
6486d7f5d3SJohn Marino int duration;
6586d7f5d3SJohn Marino int do_rt;
6686d7f5d3SJohn Marino int bench_nice;
6786d7f5d3SJohn Marino int load_nice;
6886d7f5d3SJohn Marino unsigned long custom_run;
6986d7f5d3SJohn Marino unsigned long custom_interval;
7086d7f5d3SJohn Marino unsigned long cpu_load;
7186d7f5d3SJohn Marino char logfilename[MAX_LOG_LENGTH];
7286d7f5d3SJohn Marino int log;
7386d7f5d3SJohn Marino char unamer[MAX_UNAME_LENGTH];
7486d7f5d3SJohn Marino char datestamp[13];
7586d7f5d3SJohn Marino FILE *logfile;
7686d7f5d3SJohn Marino } ud = {
7786d7f5d3SJohn Marino .duration = 30,
7886d7f5d3SJohn Marino .cpu_load = 4,
7986d7f5d3SJohn Marino .log = 1,
8086d7f5d3SJohn Marino };
8186d7f5d3SJohn Marino
8286d7f5d3SJohn Marino /* Pipes main to/from load and bench processes */
8386d7f5d3SJohn Marino static int m2l[2], l2m[2], m2b[2], b2m[2];
8486d7f5d3SJohn Marino
8586d7f5d3SJohn Marino /* Which member of becnhmarks is used when not benchmarking */
8686d7f5d3SJohn Marino #define NOT_BENCHING (THREADS)
8786d7f5d3SJohn Marino #define CUSTOM (THREADS - 1)
8886d7f5d3SJohn Marino
8986d7f5d3SJohn Marino /*
9086d7f5d3SJohn Marino * To add another load or a benchmark you need to increment the value of
9186d7f5d3SJohn Marino * THREADS, add a function prototype for your function and add an entry to
9286d7f5d3SJohn Marino * the threadlist. To specify whether the function is a benchmark or a load
9386d7f5d3SJohn Marino * set the benchmark and/or load flag as appropriate. The basic requirements
9486d7f5d3SJohn Marino * of a new load can be seen by using emulate_none as a template.
9586d7f5d3SJohn Marino */
9686d7f5d3SJohn Marino
9786d7f5d3SJohn Marino void emulate_none(struct thread *th);
9886d7f5d3SJohn Marino void emulate_audio(struct thread *th);
9986d7f5d3SJohn Marino void emulate_video(struct thread *th);
10086d7f5d3SJohn Marino void emulate_x(struct thread *th);
10186d7f5d3SJohn Marino void emulate_game(struct thread *th);
10286d7f5d3SJohn Marino void emulate_burn(struct thread *th);
10386d7f5d3SJohn Marino void emulate_write(struct thread *th);
10486d7f5d3SJohn Marino void emulate_read(struct thread *th);
10586d7f5d3SJohn Marino void emulate_ring(struct thread *th);
10686d7f5d3SJohn Marino void emulate_compile(struct thread *th);
10786d7f5d3SJohn Marino void emulate_memload(struct thread *th);
10886d7f5d3SJohn Marino void emulate_hackbench(struct thread *th);
10986d7f5d3SJohn Marino void emulate_custom(struct thread *th);
11086d7f5d3SJohn Marino
11186d7f5d3SJohn Marino struct thread threadlist[THREADS] = {
11286d7f5d3SJohn Marino {.label = "None", .name = emulate_none, .load = 1, .rtload = 1},
11386d7f5d3SJohn Marino {.label = "Audio", .name = emulate_audio, .bench = 1, .rtbench = 1},
11486d7f5d3SJohn Marino {.label = "Video", .name = emulate_video, .bench = 1, .rtbench = 1, .load = 1, .rtload = 1},
11586d7f5d3SJohn Marino {.label = "X", .name = emulate_x, .bench = 1, .load = 1, .rtload = 1},
11686d7f5d3SJohn Marino {.label = "Gaming", .name = emulate_game, .nodeadlines = 1, .bench = 1},
11786d7f5d3SJohn Marino {.label = "Burn", .name = emulate_burn, .load = 1, .rtload = 1},
11886d7f5d3SJohn Marino {.label = "Write", .name = emulate_write, .load = 1, .rtload = 1},
11986d7f5d3SJohn Marino {.label = "Read", .name = emulate_read, .load = 1, .rtload = 1},
12086d7f5d3SJohn Marino {.label = "Ring", .name = emulate_ring, .load = 0, .rtload = 0}, /* No useful data from this */
12186d7f5d3SJohn Marino {.label = "Compile", .name = emulate_compile, .load = 1, .rtload = 1},
12286d7f5d3SJohn Marino {.label = "Memload", .name = emulate_memload, .load = 1, .rtload = 1},
12386d7f5d3SJohn Marino {.label = "Hack", .name = emulate_hackbench, .load = 0, .rtload = 0}, /* This is causing signal headaches */
12486d7f5d3SJohn Marino {.label = "Custom", .name = emulate_custom}, /* Leave custom as last entry */
12586d7f5d3SJohn Marino };
12686d7f5d3SJohn Marino
12786d7f5d3SJohn Marino void init_sem(sem_t *sem);
12886d7f5d3SJohn Marino void init_all_sems(struct sems *s);
12986d7f5d3SJohn Marino void initialise_thread(int i);
13086d7f5d3SJohn Marino void start_thread(struct thread *th);
13186d7f5d3SJohn Marino void stop_thread(struct thread *th);
13286d7f5d3SJohn Marino
terminal_error(const char * name)13386d7f5d3SJohn Marino void terminal_error(const char *name)
13486d7f5d3SJohn Marino {
13586d7f5d3SJohn Marino fprintf(stderr, "\n");
13686d7f5d3SJohn Marino perror(name);
13786d7f5d3SJohn Marino exit (1);
13886d7f5d3SJohn Marino }
13986d7f5d3SJohn Marino
terminal_fileopen_error(FILE * fp,char * name)14086d7f5d3SJohn Marino void terminal_fileopen_error(FILE *fp, char *name)
14186d7f5d3SJohn Marino {
14286d7f5d3SJohn Marino if (fclose(fp) == -1)
14386d7f5d3SJohn Marino terminal_error("fclose");
14486d7f5d3SJohn Marino terminal_error(name);
14586d7f5d3SJohn Marino }
14686d7f5d3SJohn Marino
get_nsecs(struct timespec * myts)14786d7f5d3SJohn Marino unsigned long long get_nsecs(struct timespec *myts)
14886d7f5d3SJohn Marino {
14986d7f5d3SJohn Marino if (clock_gettime(CLOCK_REALTIME, myts))
15086d7f5d3SJohn Marino terminal_error("clock_gettime");
15186d7f5d3SJohn Marino return (myts->tv_sec * 1000000000 + myts->tv_nsec );
15286d7f5d3SJohn Marino }
15386d7f5d3SJohn Marino
get_usecs(struct timespec * myts)15486d7f5d3SJohn Marino unsigned long get_usecs(struct timespec *myts)
15586d7f5d3SJohn Marino {
15686d7f5d3SJohn Marino if (clock_gettime(CLOCK_REALTIME, myts))
15786d7f5d3SJohn Marino terminal_error("clock_gettime");
15886d7f5d3SJohn Marino return (myts->tv_sec * 1000000 + myts->tv_nsec / 1000 );
15986d7f5d3SJohn Marino }
16086d7f5d3SJohn Marino
set_fifo(int prio)16186d7f5d3SJohn Marino void set_fifo(int prio)
16286d7f5d3SJohn Marino {
16386d7f5d3SJohn Marino struct sched_param sp;
16486d7f5d3SJohn Marino
16586d7f5d3SJohn Marino memset(&sp, 0, sizeof(sp));
16686d7f5d3SJohn Marino sp.sched_priority = prio;
16786d7f5d3SJohn Marino if (sched_setscheduler(0, SCHED_FIFO, &sp) == -1) {
16886d7f5d3SJohn Marino if (errno != EPERM)
16986d7f5d3SJohn Marino terminal_error("sched_setscheduler");
17086d7f5d3SJohn Marino }
17186d7f5d3SJohn Marino }
17286d7f5d3SJohn Marino
set_mlock(void)17386d7f5d3SJohn Marino void set_mlock(void)
17486d7f5d3SJohn Marino {
17586d7f5d3SJohn Marino int mlockflags;
17686d7f5d3SJohn Marino
17786d7f5d3SJohn Marino mlockflags = MCL_CURRENT | MCL_FUTURE;
17886d7f5d3SJohn Marino #if 0
17986d7f5d3SJohn Marino mlockall(mlockflags); /* Is not critical if this fails */
18086d7f5d3SJohn Marino #endif
18186d7f5d3SJohn Marino }
18286d7f5d3SJohn Marino
set_munlock(void)18386d7f5d3SJohn Marino void set_munlock(void)
18486d7f5d3SJohn Marino {
18586d7f5d3SJohn Marino #if 0
18686d7f5d3SJohn Marino if (munlockall() == -1)
18786d7f5d3SJohn Marino terminal_error("munlockall");
18886d7f5d3SJohn Marino #endif
18986d7f5d3SJohn Marino }
19086d7f5d3SJohn Marino
set_thread_fifo(pthread_t pthread,int prio)19186d7f5d3SJohn Marino void set_thread_fifo(pthread_t pthread, int prio)
19286d7f5d3SJohn Marino {
19386d7f5d3SJohn Marino struct sched_param sp;
19486d7f5d3SJohn Marino memset(&sp, 0, sizeof(sp));
19586d7f5d3SJohn Marino sp.sched_priority = prio;
19686d7f5d3SJohn Marino if (pthread_setschedparam(pthread, SCHED_FIFO, &sp) == -1)
19786d7f5d3SJohn Marino terminal_error("pthread_setschedparam");
19886d7f5d3SJohn Marino }
19986d7f5d3SJohn Marino
set_normal(void)20086d7f5d3SJohn Marino void set_normal(void)
20186d7f5d3SJohn Marino {
20286d7f5d3SJohn Marino struct sched_param sp;
20386d7f5d3SJohn Marino memset(&sp, 0, sizeof(sp));
20486d7f5d3SJohn Marino sp.sched_priority = 0;
20586d7f5d3SJohn Marino if (sched_setscheduler(0, SCHED_OTHER, &sp) == -1) {
20686d7f5d3SJohn Marino fprintf(stderr, "Weird, could not unset RT scheduling!\n");
20786d7f5d3SJohn Marino }
20886d7f5d3SJohn Marino }
20986d7f5d3SJohn Marino
set_nice(int prio)21086d7f5d3SJohn Marino void set_nice(int prio)
21186d7f5d3SJohn Marino {
21286d7f5d3SJohn Marino if (setpriority(PRIO_PROCESS, 0, prio) == -1)
21386d7f5d3SJohn Marino terminal_error("setpriority");
21486d7f5d3SJohn Marino }
21586d7f5d3SJohn Marino
test_fifo(void)21686d7f5d3SJohn Marino int test_fifo(void)
21786d7f5d3SJohn Marino {
21886d7f5d3SJohn Marino struct sched_param sp;
21986d7f5d3SJohn Marino memset(&sp, 0, sizeof(sp));
22086d7f5d3SJohn Marino sp.sched_priority = 99;
22186d7f5d3SJohn Marino if (sched_setscheduler(0, SCHED_FIFO, &sp) == -1) {
22286d7f5d3SJohn Marino if (errno != EPERM)
22386d7f5d3SJohn Marino terminal_error("sched_setscheduler");
22486d7f5d3SJohn Marino goto out_fail;
22586d7f5d3SJohn Marino }
22686d7f5d3SJohn Marino if (sched_getscheduler(0) != SCHED_FIFO)
22786d7f5d3SJohn Marino goto out_fail;
22886d7f5d3SJohn Marino set_normal();
22986d7f5d3SJohn Marino return 1;
23086d7f5d3SJohn Marino out_fail:
23186d7f5d3SJohn Marino set_normal();
23286d7f5d3SJohn Marino return 0;
23386d7f5d3SJohn Marino }
23486d7f5d3SJohn Marino
set_thread_normal(pthread_t pthread)23586d7f5d3SJohn Marino void set_thread_normal(pthread_t pthread)
23686d7f5d3SJohn Marino {
23786d7f5d3SJohn Marino struct sched_param sp;
23886d7f5d3SJohn Marino memset(&sp, 0, sizeof(sp));
23986d7f5d3SJohn Marino sp.sched_priority = 0;
24086d7f5d3SJohn Marino if (pthread_setschedparam(pthread, SCHED_OTHER, &sp) == -1)
24186d7f5d3SJohn Marino terminal_error("pthread_setschedparam");
24286d7f5d3SJohn Marino }
24386d7f5d3SJohn Marino
sync_flush(void)24486d7f5d3SJohn Marino void sync_flush(void)
24586d7f5d3SJohn Marino {
24686d7f5d3SJohn Marino if ((fflush(NULL)) == EOF)
24786d7f5d3SJohn Marino terminal_error("fflush");
24886d7f5d3SJohn Marino sync();
24986d7f5d3SJohn Marino sync();
25086d7f5d3SJohn Marino sync();
25186d7f5d3SJohn Marino }
25286d7f5d3SJohn Marino
compute_allocable_mem(void)25386d7f5d3SJohn Marino unsigned long compute_allocable_mem(void)
25486d7f5d3SJohn Marino {
25586d7f5d3SJohn Marino unsigned long total = ud.ram + ud.swap;
25686d7f5d3SJohn Marino unsigned long usage = ud.ram * 110 / 100 ;
25786d7f5d3SJohn Marino
25886d7f5d3SJohn Marino /* Leave at least DEFAULT_RESERVE free space and check for maths overflow. */
25986d7f5d3SJohn Marino if (total - DEFAULT_RESERVE < usage)
26086d7f5d3SJohn Marino usage = total - DEFAULT_RESERVE;
26186d7f5d3SJohn Marino usage /= 1024; /* to megabytes */
26286d7f5d3SJohn Marino if (usage > 2930)
26386d7f5d3SJohn Marino usage = 2930;
26486d7f5d3SJohn Marino return usage;
26586d7f5d3SJohn Marino }
26686d7f5d3SJohn Marino
burn_loops(unsigned long loops)26786d7f5d3SJohn Marino void burn_loops(unsigned long loops)
26886d7f5d3SJohn Marino {
26986d7f5d3SJohn Marino unsigned long i;
27086d7f5d3SJohn Marino
27186d7f5d3SJohn Marino /*
27286d7f5d3SJohn Marino * We need some magic here to prevent the compiler from optimising
27386d7f5d3SJohn Marino * this loop away. Otherwise trying to emulate a fixed cpu load
27486d7f5d3SJohn Marino * with this loop will not work.
27586d7f5d3SJohn Marino */
27686d7f5d3SJohn Marino for (i = 0 ; i < loops ; i++)
27786d7f5d3SJohn Marino asm volatile("" : : : "memory");
27886d7f5d3SJohn Marino }
27986d7f5d3SJohn Marino
28086d7f5d3SJohn Marino /* Use this many usecs of cpu time */
burn_usecs(unsigned long usecs)28186d7f5d3SJohn Marino void burn_usecs(unsigned long usecs)
28286d7f5d3SJohn Marino {
28386d7f5d3SJohn Marino unsigned long ms_loops;
28486d7f5d3SJohn Marino
28586d7f5d3SJohn Marino ms_loops = ud.loops_per_ms / 1000 * usecs;
28686d7f5d3SJohn Marino burn_loops(ms_loops);
28786d7f5d3SJohn Marino }
28886d7f5d3SJohn Marino
microsleep(unsigned long long usecs)28986d7f5d3SJohn Marino void microsleep(unsigned long long usecs)
29086d7f5d3SJohn Marino {
29186d7f5d3SJohn Marino struct timespec req, rem;
29286d7f5d3SJohn Marino
29386d7f5d3SJohn Marino rem.tv_sec = rem.tv_nsec = 0;
29486d7f5d3SJohn Marino
29586d7f5d3SJohn Marino req.tv_sec = usecs / 1000000;
29686d7f5d3SJohn Marino req.tv_nsec = (usecs - (req.tv_sec * 1000000)) * 1000;
29786d7f5d3SJohn Marino continue_sleep:
29886d7f5d3SJohn Marino if ((nanosleep(&req, &rem)) == -1) {
29986d7f5d3SJohn Marino if (errno == EINTR) {
30086d7f5d3SJohn Marino if (rem.tv_sec || rem.tv_nsec) {
30186d7f5d3SJohn Marino req.tv_sec = rem.tv_sec;
30286d7f5d3SJohn Marino req.tv_nsec = rem.tv_nsec;
30386d7f5d3SJohn Marino goto continue_sleep;
30486d7f5d3SJohn Marino }
30586d7f5d3SJohn Marino goto out;
30686d7f5d3SJohn Marino }
30786d7f5d3SJohn Marino terminal_error("nanosleep");
30886d7f5d3SJohn Marino }
30986d7f5d3SJohn Marino out:
31086d7f5d3SJohn Marino return;
31186d7f5d3SJohn Marino }
31286d7f5d3SJohn Marino
31386d7f5d3SJohn Marino /*
31486d7f5d3SJohn Marino * Yes, sem_post and sem_wait shouldn't return -1 but they do so we must
31586d7f5d3SJohn Marino * handle it.
31686d7f5d3SJohn Marino */
post_sem(sem_t * s)31786d7f5d3SJohn Marino inline void post_sem(sem_t *s)
31886d7f5d3SJohn Marino {
31986d7f5d3SJohn Marino retry:
32086d7f5d3SJohn Marino if ((sem_post(s)) == -1) {
32186d7f5d3SJohn Marino if (errno == EINTR)
32286d7f5d3SJohn Marino goto retry;
32386d7f5d3SJohn Marino terminal_error("sem_post");
32486d7f5d3SJohn Marino }
32586d7f5d3SJohn Marino }
32686d7f5d3SJohn Marino
wait_sem(sem_t * s)32786d7f5d3SJohn Marino inline void wait_sem(sem_t *s)
32886d7f5d3SJohn Marino {
32986d7f5d3SJohn Marino retry:
33086d7f5d3SJohn Marino if ((sem_wait(s)) == -1) {
33186d7f5d3SJohn Marino if (errno == EINTR)
33286d7f5d3SJohn Marino goto retry;
33386d7f5d3SJohn Marino terminal_error("sem_wait");
33486d7f5d3SJohn Marino }
33586d7f5d3SJohn Marino }
33686d7f5d3SJohn Marino
trywait_sem(sem_t * s)33786d7f5d3SJohn Marino inline int trywait_sem(sem_t *s)
33886d7f5d3SJohn Marino {
33986d7f5d3SJohn Marino int ret;
34086d7f5d3SJohn Marino
34186d7f5d3SJohn Marino retry:
34286d7f5d3SJohn Marino if ((ret = sem_trywait(s)) == -1) {
34386d7f5d3SJohn Marino if (errno == EINTR)
34486d7f5d3SJohn Marino goto retry;
34586d7f5d3SJohn Marino if (errno != EAGAIN)
34686d7f5d3SJohn Marino terminal_error("sem_trywait");
34786d7f5d3SJohn Marino }
34886d7f5d3SJohn Marino return ret;
34986d7f5d3SJohn Marino }
35086d7f5d3SJohn Marino
Read(int fd,void * buf,size_t count)35186d7f5d3SJohn Marino inline ssize_t Read(int fd, void *buf, size_t count)
35286d7f5d3SJohn Marino {
35386d7f5d3SJohn Marino ssize_t retval;
35486d7f5d3SJohn Marino
35586d7f5d3SJohn Marino retry:
35686d7f5d3SJohn Marino retval = read(fd, buf, count);
35786d7f5d3SJohn Marino if (retval == -1) {
35886d7f5d3SJohn Marino if (errno == EINTR)
35986d7f5d3SJohn Marino goto retry;
36086d7f5d3SJohn Marino terminal_error("read");
36186d7f5d3SJohn Marino }
36286d7f5d3SJohn Marino return retval;
36386d7f5d3SJohn Marino }
36486d7f5d3SJohn Marino
Write(int fd,const void * buf,size_t count)36586d7f5d3SJohn Marino inline ssize_t Write(int fd, const void *buf, size_t count)
36686d7f5d3SJohn Marino {
36786d7f5d3SJohn Marino ssize_t retval;
36886d7f5d3SJohn Marino
36986d7f5d3SJohn Marino retry:
37086d7f5d3SJohn Marino retval = write(fd, &buf, count);
37186d7f5d3SJohn Marino if (retval == -1) {
37286d7f5d3SJohn Marino if (errno == EINTR)
37386d7f5d3SJohn Marino goto retry;
37486d7f5d3SJohn Marino terminal_error("write");
37586d7f5d3SJohn Marino }
37686d7f5d3SJohn Marino return retval;
37786d7f5d3SJohn Marino }
37886d7f5d3SJohn Marino
periodic_schedule(struct thread * th,unsigned long run_usecs,unsigned long interval_usecs,unsigned long long deadline)37986d7f5d3SJohn Marino unsigned long periodic_schedule(struct thread *th, unsigned long run_usecs,
38086d7f5d3SJohn Marino unsigned long interval_usecs, unsigned long long deadline)
38186d7f5d3SJohn Marino {
38286d7f5d3SJohn Marino unsigned long long latency, missed_latency;
38386d7f5d3SJohn Marino unsigned long long current_time;
38486d7f5d3SJohn Marino struct tk_thread *tk;
38586d7f5d3SJohn Marino struct data_table *tb;
38686d7f5d3SJohn Marino struct timespec myts;
38786d7f5d3SJohn Marino
38886d7f5d3SJohn Marino latency = 0;
38986d7f5d3SJohn Marino tb = th->dt;
39086d7f5d3SJohn Marino tk = &th->tkthread;
39186d7f5d3SJohn Marino
39286d7f5d3SJohn Marino current_time = get_usecs(&myts);
39386d7f5d3SJohn Marino if (current_time > deadline + tk->slept_interval)
39486d7f5d3SJohn Marino latency = current_time - deadline- tk->slept_interval;
39586d7f5d3SJohn Marino
39686d7f5d3SJohn Marino /* calculate the latency for missed frames */
39786d7f5d3SJohn Marino missed_latency = 0;
39886d7f5d3SJohn Marino
39986d7f5d3SJohn Marino current_time = get_usecs(&myts);
40086d7f5d3SJohn Marino if (interval_usecs && current_time > deadline + interval_usecs) {
40186d7f5d3SJohn Marino /* We missed the deadline even before we consumed cpu */
40286d7f5d3SJohn Marino unsigned long intervals;
40386d7f5d3SJohn Marino
40486d7f5d3SJohn Marino deadline += interval_usecs;
40586d7f5d3SJohn Marino intervals = (current_time - deadline) /
40686d7f5d3SJohn Marino interval_usecs + 1;
40786d7f5d3SJohn Marino
40886d7f5d3SJohn Marino tb->missed_deadlines += intervals;
40986d7f5d3SJohn Marino missed_latency = intervals * interval_usecs;
41086d7f5d3SJohn Marino deadline += intervals * interval_usecs;
41186d7f5d3SJohn Marino tb->missed_burns += intervals;
41286d7f5d3SJohn Marino goto bypass_burn;
41386d7f5d3SJohn Marino }
41486d7f5d3SJohn Marino
41586d7f5d3SJohn Marino burn_usecs(run_usecs);
41686d7f5d3SJohn Marino current_time = get_usecs(&myts);
41786d7f5d3SJohn Marino tb->achieved_burns++;
41886d7f5d3SJohn Marino
41986d7f5d3SJohn Marino /*
42086d7f5d3SJohn Marino * If we meet the deadline we move the deadline forward, otherwise
42186d7f5d3SJohn Marino * we consider it a missed deadline and dropped frame etc.
42286d7f5d3SJohn Marino */
42386d7f5d3SJohn Marino deadline += interval_usecs;
42486d7f5d3SJohn Marino if (deadline >= current_time) {
42586d7f5d3SJohn Marino tb->deadlines_met++;
42686d7f5d3SJohn Marino } else {
42786d7f5d3SJohn Marino if (interval_usecs) {
42886d7f5d3SJohn Marino unsigned long intervals = (current_time - deadline) /
42986d7f5d3SJohn Marino interval_usecs + 1;
43086d7f5d3SJohn Marino
43186d7f5d3SJohn Marino tb->missed_deadlines += intervals;
43286d7f5d3SJohn Marino missed_latency = intervals * interval_usecs;
43386d7f5d3SJohn Marino deadline += intervals * interval_usecs;
43486d7f5d3SJohn Marino if (intervals > 1)
43586d7f5d3SJohn Marino tb->missed_burns += intervals;
43686d7f5d3SJohn Marino } else {
43786d7f5d3SJohn Marino deadline = current_time;
43886d7f5d3SJohn Marino goto out_nosleep;
43986d7f5d3SJohn Marino }
44086d7f5d3SJohn Marino }
44186d7f5d3SJohn Marino bypass_burn:
44286d7f5d3SJohn Marino tk->sleep_interval = deadline - current_time;
44386d7f5d3SJohn Marino
44486d7f5d3SJohn Marino post_sem(&tk->sem.start);
44586d7f5d3SJohn Marino wait_sem(&tk->sem.complete);
44686d7f5d3SJohn Marino out_nosleep:
44786d7f5d3SJohn Marino /*
44886d7f5d3SJohn Marino * Must add missed_latency to total here as this function may not be
44986d7f5d3SJohn Marino * called again and the missed latency can be lost
45086d7f5d3SJohn Marino */
45186d7f5d3SJohn Marino latency += missed_latency;
45286d7f5d3SJohn Marino if (latency > tb->max_latency)
45386d7f5d3SJohn Marino tb->max_latency = latency;
45486d7f5d3SJohn Marino tb->total_latency += latency;
45586d7f5d3SJohn Marino tb->sum_latency_squared += latency * latency;
45686d7f5d3SJohn Marino tb->nr_samples++;
45786d7f5d3SJohn Marino
45886d7f5d3SJohn Marino return deadline;
45986d7f5d3SJohn Marino }
46086d7f5d3SJohn Marino
initialise_thread_data(struct data_table * tb)46186d7f5d3SJohn Marino void initialise_thread_data(struct data_table *tb)
46286d7f5d3SJohn Marino {
46386d7f5d3SJohn Marino tb->max_latency =
46486d7f5d3SJohn Marino tb->total_latency =
46586d7f5d3SJohn Marino tb->sum_latency_squared =
46686d7f5d3SJohn Marino tb->deadlines_met =
46786d7f5d3SJohn Marino tb->missed_deadlines =
46886d7f5d3SJohn Marino tb->missed_burns =
46986d7f5d3SJohn Marino tb->nr_samples = 0;
47086d7f5d3SJohn Marino }
47186d7f5d3SJohn Marino
create_pthread(pthread_t * thread,pthread_attr_t * attr,void * (* start_routine)(void *),void * arg)47286d7f5d3SJohn Marino void create_pthread(pthread_t * thread, pthread_attr_t * attr,
47386d7f5d3SJohn Marino void * (*start_routine)(void *), void *arg)
47486d7f5d3SJohn Marino {
47586d7f5d3SJohn Marino if (pthread_create(thread, attr, start_routine, arg))
47686d7f5d3SJohn Marino terminal_error("pthread_create");
47786d7f5d3SJohn Marino }
47886d7f5d3SJohn Marino
join_pthread(pthread_t th,void ** thread_return)47986d7f5d3SJohn Marino void join_pthread(pthread_t th, void **thread_return)
48086d7f5d3SJohn Marino {
48186d7f5d3SJohn Marino if (pthread_join(th, thread_return))
48286d7f5d3SJohn Marino terminal_error("pthread_join");
48386d7f5d3SJohn Marino }
48486d7f5d3SJohn Marino
emulate_none(struct thread * th)48586d7f5d3SJohn Marino void emulate_none(struct thread *th)
48686d7f5d3SJohn Marino {
48786d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
48886d7f5d3SJohn Marino wait_sem(s);
48986d7f5d3SJohn Marino }
49086d7f5d3SJohn Marino
49186d7f5d3SJohn Marino #define AUDIO_INTERVAL (50000)
49286d7f5d3SJohn Marino #define AUDIO_RUN (AUDIO_INTERVAL / 20)
49386d7f5d3SJohn Marino /* We emulate audio by using 5% cpu and waking every 50ms */
emulate_audio(struct thread * th)49486d7f5d3SJohn Marino void emulate_audio(struct thread *th)
49586d7f5d3SJohn Marino {
49686d7f5d3SJohn Marino unsigned long long deadline;
49786d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
49886d7f5d3SJohn Marino struct timespec myts;
49986d7f5d3SJohn Marino
50086d7f5d3SJohn Marino th->decasecond_deadlines = 1000000 / AUDIO_INTERVAL * 10;
50186d7f5d3SJohn Marino deadline = get_usecs(&myts);
50286d7f5d3SJohn Marino
50386d7f5d3SJohn Marino while (1) {
50486d7f5d3SJohn Marino deadline = periodic_schedule(th, AUDIO_RUN, AUDIO_INTERVAL,
50586d7f5d3SJohn Marino deadline);
50686d7f5d3SJohn Marino if (!trywait_sem(s))
50786d7f5d3SJohn Marino return;
50886d7f5d3SJohn Marino }
50986d7f5d3SJohn Marino }
51086d7f5d3SJohn Marino
51186d7f5d3SJohn Marino /* We emulate video by using 40% cpu and waking for 60fps */
51286d7f5d3SJohn Marino #define VIDEO_INTERVAL (1000000 / 60)
51386d7f5d3SJohn Marino #define VIDEO_RUN (VIDEO_INTERVAL * 40 / 100)
emulate_video(struct thread * th)51486d7f5d3SJohn Marino void emulate_video(struct thread *th)
51586d7f5d3SJohn Marino {
51686d7f5d3SJohn Marino unsigned long long deadline;
51786d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
51886d7f5d3SJohn Marino struct timespec myts;
51986d7f5d3SJohn Marino
52086d7f5d3SJohn Marino th->decasecond_deadlines = 1000000 / VIDEO_INTERVAL * 10;
52186d7f5d3SJohn Marino deadline = get_usecs(&myts);
52286d7f5d3SJohn Marino
52386d7f5d3SJohn Marino while (1) {
52486d7f5d3SJohn Marino deadline = periodic_schedule(th, VIDEO_RUN, VIDEO_INTERVAL,
52586d7f5d3SJohn Marino deadline);
52686d7f5d3SJohn Marino if (!trywait_sem(s))
52786d7f5d3SJohn Marino return;
52886d7f5d3SJohn Marino }
52986d7f5d3SJohn Marino }
53086d7f5d3SJohn Marino
53186d7f5d3SJohn Marino /*
53286d7f5d3SJohn Marino * We emulate X by running for a variable percentage of cpu from 0-100%
53386d7f5d3SJohn Marino * in 1ms chunks.
53486d7f5d3SJohn Marino */
emulate_x(struct thread * th)53586d7f5d3SJohn Marino void emulate_x(struct thread *th)
53686d7f5d3SJohn Marino {
53786d7f5d3SJohn Marino unsigned long long deadline;
53886d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
53986d7f5d3SJohn Marino struct timespec myts;
54086d7f5d3SJohn Marino
54186d7f5d3SJohn Marino th->decasecond_deadlines = 100;
54286d7f5d3SJohn Marino deadline = get_usecs(&myts);
54386d7f5d3SJohn Marino
54486d7f5d3SJohn Marino while (1) {
54586d7f5d3SJohn Marino int i, j;
54686d7f5d3SJohn Marino for (i = 0 ; i <= 100 ; i++) {
54786d7f5d3SJohn Marino j = 100 - i;
54886d7f5d3SJohn Marino deadline = periodic_schedule(th, i * 1000, j * 1000,
54986d7f5d3SJohn Marino deadline);
55086d7f5d3SJohn Marino deadline += i * 1000;
55186d7f5d3SJohn Marino if (!trywait_sem(s))
55286d7f5d3SJohn Marino return;
55386d7f5d3SJohn Marino }
55486d7f5d3SJohn Marino }
55586d7f5d3SJohn Marino }
55686d7f5d3SJohn Marino
55786d7f5d3SJohn Marino /*
55886d7f5d3SJohn Marino * We emulate gaming by using 100% cpu and seeing how many frames (jobs
55986d7f5d3SJohn Marino * completed) we can do in that time. Deadlines are meaningless with
56086d7f5d3SJohn Marino * unlocked frame rates. We do not use periodic schedule because for
56186d7f5d3SJohn Marino * this load because this never wants to sleep.
56286d7f5d3SJohn Marino */
56386d7f5d3SJohn Marino #define GAME_INTERVAL (100000)
56486d7f5d3SJohn Marino #define GAME_RUN (GAME_INTERVAL)
emulate_game(struct thread * th)56586d7f5d3SJohn Marino void emulate_game(struct thread *th)
56686d7f5d3SJohn Marino {
56786d7f5d3SJohn Marino unsigned long long deadline, current_time, latency;
56886d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
56986d7f5d3SJohn Marino struct timespec myts;
57086d7f5d3SJohn Marino struct data_table *tb;
57186d7f5d3SJohn Marino
57286d7f5d3SJohn Marino tb = th->dt;
57386d7f5d3SJohn Marino th->decasecond_deadlines = 1000000 / GAME_INTERVAL * 10;
57486d7f5d3SJohn Marino
57586d7f5d3SJohn Marino while (1) {
57686d7f5d3SJohn Marino deadline = get_usecs(&myts) + GAME_INTERVAL;
57786d7f5d3SJohn Marino burn_usecs(GAME_RUN);
57886d7f5d3SJohn Marino current_time = get_usecs(&myts);
57986d7f5d3SJohn Marino /* use usecs instead of simple count for game burn statistics */
58086d7f5d3SJohn Marino tb->achieved_burns += GAME_RUN;
58186d7f5d3SJohn Marino if (current_time > deadline) {
58286d7f5d3SJohn Marino latency = current_time - deadline;
58386d7f5d3SJohn Marino tb->missed_burns += latency;
58486d7f5d3SJohn Marino } else
58586d7f5d3SJohn Marino latency = 0;
58686d7f5d3SJohn Marino if (latency > tb->max_latency)
58786d7f5d3SJohn Marino tb->max_latency = latency;
58886d7f5d3SJohn Marino tb->total_latency += latency;
58986d7f5d3SJohn Marino tb->sum_latency_squared += latency * latency;
59086d7f5d3SJohn Marino tb->nr_samples++;
59186d7f5d3SJohn Marino if (!trywait_sem(s))
59286d7f5d3SJohn Marino return;
59386d7f5d3SJohn Marino }
59486d7f5d3SJohn Marino }
59586d7f5d3SJohn Marino
burn_thread(void * t)59686d7f5d3SJohn Marino void *burn_thread(void *t)
59786d7f5d3SJohn Marino {
59886d7f5d3SJohn Marino struct thread *th;
59986d7f5d3SJohn Marino sem_t *s;
60086d7f5d3SJohn Marino long i = (long)t;
60186d7f5d3SJohn Marino
60286d7f5d3SJohn Marino th = &threadlist[i];
60386d7f5d3SJohn Marino s = &th->sem.stopchild;
60486d7f5d3SJohn Marino
60586d7f5d3SJohn Marino while (1) {
60686d7f5d3SJohn Marino burn_loops(ud.loops_per_ms);
60786d7f5d3SJohn Marino if (!trywait_sem(s)) {
60886d7f5d3SJohn Marino post_sem(s);
60986d7f5d3SJohn Marino break;
61086d7f5d3SJohn Marino }
61186d7f5d3SJohn Marino }
61286d7f5d3SJohn Marino return NULL;
61386d7f5d3SJohn Marino }
61486d7f5d3SJohn Marino
61586d7f5d3SJohn Marino /* Have ud.cpu_load threads burn cpu continuously */
emulate_burn(struct thread * th)61686d7f5d3SJohn Marino void emulate_burn(struct thread *th)
61786d7f5d3SJohn Marino {
61886d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
61986d7f5d3SJohn Marino unsigned long i;
62086d7f5d3SJohn Marino long t;
62186d7f5d3SJohn Marino pthread_t burnthreads[ud.cpu_load];
62286d7f5d3SJohn Marino
62386d7f5d3SJohn Marino t = th->threadno;
62486d7f5d3SJohn Marino for (i = 0 ; i < ud.cpu_load ; i++)
62586d7f5d3SJohn Marino create_pthread(&burnthreads[i], NULL, burn_thread,
62686d7f5d3SJohn Marino (void*)(long) t);
62786d7f5d3SJohn Marino wait_sem(s);
62886d7f5d3SJohn Marino post_sem(&th->sem.stopchild);
62986d7f5d3SJohn Marino for (i = 0 ; i < ud.cpu_load ; i++)
63086d7f5d3SJohn Marino join_pthread(burnthreads[i], NULL);
63186d7f5d3SJohn Marino }
63286d7f5d3SJohn Marino
63386d7f5d3SJohn Marino /* Write a file the size of ram continuously */
emulate_write(struct thread * th)63486d7f5d3SJohn Marino void emulate_write(struct thread *th)
63586d7f5d3SJohn Marino {
63686d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
63786d7f5d3SJohn Marino FILE *fp;
63886d7f5d3SJohn Marino char *name = "interbench.write";
63986d7f5d3SJohn Marino void *buf = NULL;
64086d7f5d3SJohn Marino struct stat statbuf;
64186d7f5d3SJohn Marino unsigned long mem;
64286d7f5d3SJohn Marino
64386d7f5d3SJohn Marino if (!(fp = fopen(name, "w")))
64486d7f5d3SJohn Marino terminal_error("fopen");
64586d7f5d3SJohn Marino if (stat(name, &statbuf) == -1)
64686d7f5d3SJohn Marino terminal_fileopen_error(fp, "stat");
64786d7f5d3SJohn Marino if (statbuf.st_blksize < MIN_BLK_SIZE)
64886d7f5d3SJohn Marino statbuf.st_blksize = MIN_BLK_SIZE;
64986d7f5d3SJohn Marino mem = ud.ram / (statbuf.st_blksize / 1024); /* kilobytes to blocks */
65086d7f5d3SJohn Marino if (!(buf = calloc(1, statbuf.st_blksize)))
65186d7f5d3SJohn Marino terminal_fileopen_error(fp, "calloc");
65286d7f5d3SJohn Marino if (fclose(fp) == -1)
65386d7f5d3SJohn Marino terminal_error("fclose");
65486d7f5d3SJohn Marino
65586d7f5d3SJohn Marino while (1) {
65686d7f5d3SJohn Marino unsigned int i;
65786d7f5d3SJohn Marino
65886d7f5d3SJohn Marino if (!(fp = fopen(name, "w")))
65986d7f5d3SJohn Marino terminal_error("fopen");
66086d7f5d3SJohn Marino if (stat(name, &statbuf) == -1)
66186d7f5d3SJohn Marino terminal_fileopen_error(fp, "stat");
66286d7f5d3SJohn Marino for (i = 0 ; i < mem; i++) {
66386d7f5d3SJohn Marino if (fwrite(buf, statbuf.st_blksize, 1, fp) != 1)
66486d7f5d3SJohn Marino terminal_fileopen_error(fp, "fwrite");
66586d7f5d3SJohn Marino if (!trywait_sem(s))
66686d7f5d3SJohn Marino goto out;
66786d7f5d3SJohn Marino }
66886d7f5d3SJohn Marino if (fclose(fp) == -1)
66986d7f5d3SJohn Marino terminal_error("fclose");
67086d7f5d3SJohn Marino }
67186d7f5d3SJohn Marino
67286d7f5d3SJohn Marino out:
67386d7f5d3SJohn Marino if (fclose(fp) == -1)
67486d7f5d3SJohn Marino terminal_error("fclose");
67586d7f5d3SJohn Marino if (remove(name) == -1)
67686d7f5d3SJohn Marino terminal_error("remove");
67786d7f5d3SJohn Marino sync_flush();
67886d7f5d3SJohn Marino }
67986d7f5d3SJohn Marino
68086d7f5d3SJohn Marino /* Read a file the size of ram continuously */
emulate_read(struct thread * th)68186d7f5d3SJohn Marino void emulate_read(struct thread *th)
68286d7f5d3SJohn Marino {
68386d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
68486d7f5d3SJohn Marino char *name = "interbench.read";
68586d7f5d3SJohn Marino void *buf = NULL;
68686d7f5d3SJohn Marino struct stat statbuf;
68786d7f5d3SJohn Marino unsigned long bsize;
68886d7f5d3SJohn Marino int tmp;
68986d7f5d3SJohn Marino
69086d7f5d3SJohn Marino if ((tmp = open(name, O_RDONLY)) == -1)
69186d7f5d3SJohn Marino terminal_error("open");
69286d7f5d3SJohn Marino if (stat(name, &statbuf) == -1)
69386d7f5d3SJohn Marino terminal_error("stat");
69486d7f5d3SJohn Marino bsize = statbuf.st_blksize;
69586d7f5d3SJohn Marino if (!(buf = malloc(bsize)))
69686d7f5d3SJohn Marino terminal_error("malloc");
69786d7f5d3SJohn Marino
69886d7f5d3SJohn Marino while (1) {
69986d7f5d3SJohn Marino int rd;
70086d7f5d3SJohn Marino
70186d7f5d3SJohn Marino /*
70286d7f5d3SJohn Marino * We have to read the whole file before quitting the load
70386d7f5d3SJohn Marino * to prevent the data being cached for the next read. This
70486d7f5d3SJohn Marino * is also the reason the file is the size of physical ram.
70586d7f5d3SJohn Marino */
70686d7f5d3SJohn Marino while ((rd = Read(tmp , buf, bsize)) > 0);
70786d7f5d3SJohn Marino if(!trywait_sem(s))
70886d7f5d3SJohn Marino return;
70986d7f5d3SJohn Marino if (lseek(tmp, (off_t)0, SEEK_SET) == -1)
71086d7f5d3SJohn Marino terminal_error("lseek");
71186d7f5d3SJohn Marino }
71286d7f5d3SJohn Marino }
71386d7f5d3SJohn Marino
71486d7f5d3SJohn Marino #define RINGTHREADS 4
71586d7f5d3SJohn Marino
71686d7f5d3SJohn Marino struct thread ringthreads[RINGTHREADS];
71786d7f5d3SJohn Marino
ring_thread(void * t)71886d7f5d3SJohn Marino void *ring_thread(void *t)
71986d7f5d3SJohn Marino {
72086d7f5d3SJohn Marino struct thread *th;
72186d7f5d3SJohn Marino struct sems *s;
72286d7f5d3SJohn Marino int i, post_to;
72386d7f5d3SJohn Marino
72486d7f5d3SJohn Marino i = (long)t;
72586d7f5d3SJohn Marino th = &ringthreads[i];
72686d7f5d3SJohn Marino s = &th->sem;
72786d7f5d3SJohn Marino post_to = i + 1;
72886d7f5d3SJohn Marino if (post_to == RINGTHREADS)
72986d7f5d3SJohn Marino post_to = 0;
73086d7f5d3SJohn Marino if (i == 0)
73186d7f5d3SJohn Marino post_sem(&s->ready);
73286d7f5d3SJohn Marino
73386d7f5d3SJohn Marino while (1) {
73486d7f5d3SJohn Marino wait_sem(&s->start);
73586d7f5d3SJohn Marino post_sem(&ringthreads[post_to].sem.start);
73686d7f5d3SJohn Marino if (!trywait_sem(&s->stop))
73786d7f5d3SJohn Marino goto out;
73886d7f5d3SJohn Marino }
73986d7f5d3SJohn Marino out:
74086d7f5d3SJohn Marino post_sem(&ringthreads[post_to].sem.start);
74186d7f5d3SJohn Marino post_sem(&s->complete);
74286d7f5d3SJohn Marino return NULL;
74386d7f5d3SJohn Marino }
74486d7f5d3SJohn Marino
74586d7f5d3SJohn Marino /* Create a ring of 4 processes that wake each other up in a circle */
emulate_ring(struct thread * th)74686d7f5d3SJohn Marino void emulate_ring(struct thread *th)
74786d7f5d3SJohn Marino {
74886d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
74986d7f5d3SJohn Marino int i;
75086d7f5d3SJohn Marino
75186d7f5d3SJohn Marino for (i = 0 ; i < RINGTHREADS ; i++) {
75286d7f5d3SJohn Marino init_all_sems(&ringthreads[i].sem);
75386d7f5d3SJohn Marino create_pthread(&ringthreads[i].pthread, NULL,
75486d7f5d3SJohn Marino ring_thread, (void*)(long) i);
75586d7f5d3SJohn Marino }
75686d7f5d3SJohn Marino
75786d7f5d3SJohn Marino wait_sem(&ringthreads[0].sem.ready);
75886d7f5d3SJohn Marino post_sem(&ringthreads[0].sem.start);
75986d7f5d3SJohn Marino wait_sem(s);
76086d7f5d3SJohn Marino for (i = 0 ; i < RINGTHREADS ; i++)
76186d7f5d3SJohn Marino post_sem(&ringthreads[i].sem.stop);
76286d7f5d3SJohn Marino for (i = 0 ; i < RINGTHREADS ; i++) {
76386d7f5d3SJohn Marino wait_sem(&ringthreads[i].sem.complete);
76486d7f5d3SJohn Marino join_pthread(ringthreads[i].pthread, NULL);
76586d7f5d3SJohn Marino }
76686d7f5d3SJohn Marino }
76786d7f5d3SJohn Marino
76886d7f5d3SJohn Marino /* We emulate a compile by running burn, write and read threads simultaneously */
emulate_compile(struct thread * th)76986d7f5d3SJohn Marino void emulate_compile(struct thread *th)
77086d7f5d3SJohn Marino {
77186d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
77286d7f5d3SJohn Marino unsigned long i, threads[3];
77386d7f5d3SJohn Marino
77486d7f5d3SJohn Marino bzero(threads, 3 * sizeof(threads[0]));
77586d7f5d3SJohn Marino
77686d7f5d3SJohn Marino for (i = 0 ; i < THREADS ; i++) {
77786d7f5d3SJohn Marino if (strcmp(threadlist[i].label, "Burn") == 0)
77886d7f5d3SJohn Marino threads[0] = i;
77986d7f5d3SJohn Marino if (strcmp(threadlist[i].label, "Write") == 0)
78086d7f5d3SJohn Marino threads[1] = i;
78186d7f5d3SJohn Marino if (strcmp(threadlist[i].label, "Read") == 0)
78286d7f5d3SJohn Marino threads[2] = i;
78386d7f5d3SJohn Marino }
78486d7f5d3SJohn Marino for (i = 0 ; i < 3 ; i++) {
78586d7f5d3SJohn Marino if (!threads[i]) {
78686d7f5d3SJohn Marino fprintf(stderr, "Can't find all threads for compile load\n");
78786d7f5d3SJohn Marino exit(1);
78886d7f5d3SJohn Marino }
78986d7f5d3SJohn Marino }
79086d7f5d3SJohn Marino for (i = 0 ; i < 3 ; i++) {
79186d7f5d3SJohn Marino initialise_thread(threads[i]);
79286d7f5d3SJohn Marino start_thread(&threadlist[threads[i]]);
79386d7f5d3SJohn Marino }
79486d7f5d3SJohn Marino wait_sem(s);
79586d7f5d3SJohn Marino for (i = 0 ; i < 3 ; i++)
79686d7f5d3SJohn Marino stop_thread(&threadlist[threads[i]]);
79786d7f5d3SJohn Marino }
79886d7f5d3SJohn Marino
grab_and_touch(char * block[],int i)79986d7f5d3SJohn Marino int *grab_and_touch (char *block[], int i)
80086d7f5d3SJohn Marino {
80186d7f5d3SJohn Marino block[i] = (char *) malloc(MB);
80286d7f5d3SJohn Marino if (!block[i])
80386d7f5d3SJohn Marino return NULL;
80486d7f5d3SJohn Marino return (memset(block[i], 1, MB));
80586d7f5d3SJohn Marino }
80686d7f5d3SJohn Marino
80786d7f5d3SJohn Marino /* We emulate a memory load by allocating and torturing 110% of available ram */
emulate_memload(struct thread * th)80886d7f5d3SJohn Marino void emulate_memload(struct thread *th)
80986d7f5d3SJohn Marino {
81086d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
81186d7f5d3SJohn Marino unsigned long touchable_mem, i;
81286d7f5d3SJohn Marino char *mem_block[MAX_MEM_IN_MB];
81386d7f5d3SJohn Marino void *success;
81486d7f5d3SJohn Marino
81586d7f5d3SJohn Marino touchable_mem = compute_allocable_mem();
81686d7f5d3SJohn Marino /* loop until we're killed, frobbing memory in various perverted ways */
81786d7f5d3SJohn Marino while (1) {
81886d7f5d3SJohn Marino for (i = 0; i < touchable_mem; i++) {
81986d7f5d3SJohn Marino success = grab_and_touch(mem_block, i);
82086d7f5d3SJohn Marino if (!success) {
82186d7f5d3SJohn Marino touchable_mem = i-1;
82286d7f5d3SJohn Marino break;
82386d7f5d3SJohn Marino }
82486d7f5d3SJohn Marino }
82586d7f5d3SJohn Marino if (!trywait_sem(s))
82686d7f5d3SJohn Marino goto out_freemem;
82786d7f5d3SJohn Marino for (i = 0; i < touchable_mem; i++) {
82886d7f5d3SJohn Marino memcpy(mem_block[i], mem_block[(i + touchable_mem / 2) %
82986d7f5d3SJohn Marino touchable_mem], MB);
83086d7f5d3SJohn Marino if (!trywait_sem(s))
83186d7f5d3SJohn Marino goto out_freemem;
83286d7f5d3SJohn Marino }
83386d7f5d3SJohn Marino for (i = 0; i < touchable_mem; i++) {
83486d7f5d3SJohn Marino free(mem_block[i]);
83586d7f5d3SJohn Marino }
83686d7f5d3SJohn Marino if (!trywait_sem(s))
83786d7f5d3SJohn Marino goto out;
83886d7f5d3SJohn Marino }
83986d7f5d3SJohn Marino out_freemem:
84086d7f5d3SJohn Marino for (i = 0; i < touchable_mem; i++)
84186d7f5d3SJohn Marino free(mem_block[i]);
84286d7f5d3SJohn Marino out:
84386d7f5d3SJohn Marino return;
84486d7f5d3SJohn Marino }
84586d7f5d3SJohn Marino
84686d7f5d3SJohn Marino struct thread hackthread;
84786d7f5d3SJohn Marino
emulate_hackbench(struct thread * th)84886d7f5d3SJohn Marino void emulate_hackbench(struct thread *th)
84986d7f5d3SJohn Marino {
85086d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
85186d7f5d3SJohn Marino
85286d7f5d3SJohn Marino init_all_sems(&hackthread.sem);
85386d7f5d3SJohn Marino create_pthread(&hackthread.pthread, NULL, hackbench_thread, (void *) 0);
85486d7f5d3SJohn Marino
85586d7f5d3SJohn Marino wait_sem(s);
85686d7f5d3SJohn Marino
85786d7f5d3SJohn Marino post_sem(&hackthread.sem.stop);
85886d7f5d3SJohn Marino wait_sem(&hackthread.sem.complete);
85986d7f5d3SJohn Marino
86086d7f5d3SJohn Marino join_pthread(hackthread.pthread, NULL);
86186d7f5d3SJohn Marino }
86286d7f5d3SJohn Marino
86386d7f5d3SJohn Marino #define CUSTOM_INTERVAL (ud.custom_interval)
86486d7f5d3SJohn Marino #define CUSTOM_RUN (ud.custom_run)
emulate_custom(struct thread * th)86586d7f5d3SJohn Marino void emulate_custom(struct thread *th)
86686d7f5d3SJohn Marino {
86786d7f5d3SJohn Marino unsigned long long deadline;
86886d7f5d3SJohn Marino sem_t *s = &th->sem.stop;
86986d7f5d3SJohn Marino struct timespec myts;
87086d7f5d3SJohn Marino
87186d7f5d3SJohn Marino th->decasecond_deadlines = 1000000 / CUSTOM_INTERVAL * 10;
87286d7f5d3SJohn Marino deadline = get_usecs(&myts);
87386d7f5d3SJohn Marino
87486d7f5d3SJohn Marino while (1) {
87586d7f5d3SJohn Marino deadline = periodic_schedule(th, CUSTOM_RUN, CUSTOM_INTERVAL,
87686d7f5d3SJohn Marino deadline);
87786d7f5d3SJohn Marino if (!trywait_sem(s))
87886d7f5d3SJohn Marino return;
87986d7f5d3SJohn Marino }
88086d7f5d3SJohn Marino }
88186d7f5d3SJohn Marino
timekeeping_thread(void * t)88286d7f5d3SJohn Marino void *timekeeping_thread(void *t)
88386d7f5d3SJohn Marino {
88486d7f5d3SJohn Marino struct thread *th;
88586d7f5d3SJohn Marino struct tk_thread *tk;
88686d7f5d3SJohn Marino struct sems *s;
88786d7f5d3SJohn Marino struct timespec myts;
88886d7f5d3SJohn Marino long i = (long)t;
88986d7f5d3SJohn Marino
89086d7f5d3SJohn Marino th = &threadlist[i];
89186d7f5d3SJohn Marino tk = &th->tkthread;
89286d7f5d3SJohn Marino s = &th->tkthread.sem;
89386d7f5d3SJohn Marino /*
89486d7f5d3SJohn Marino * If this timekeeping thread is that of a benchmarked thread we run
89586d7f5d3SJohn Marino * even higher priority than the benched thread is if running real
89686d7f5d3SJohn Marino * time. Otherwise, the load timekeeping thread, which does not need
89786d7f5d3SJohn Marino * accurate accounting remains SCHED_NORMAL;
89886d7f5d3SJohn Marino */
89986d7f5d3SJohn Marino if (th->dt != &th->benchmarks[NOT_BENCHING])
90086d7f5d3SJohn Marino set_fifo(96);
90186d7f5d3SJohn Marino /* These values must be changed at the appropriate places or race */
90286d7f5d3SJohn Marino tk->sleep_interval = tk->slept_interval = 0;
90386d7f5d3SJohn Marino post_sem(&s->ready);
90486d7f5d3SJohn Marino
90586d7f5d3SJohn Marino while (1) {
90686d7f5d3SJohn Marino unsigned long start_time, now;
90786d7f5d3SJohn Marino
90886d7f5d3SJohn Marino if (!trywait_sem(&s->stop))
90986d7f5d3SJohn Marino goto out;
91086d7f5d3SJohn Marino wait_sem(&s->start);
91186d7f5d3SJohn Marino tk->slept_interval = 0;
91286d7f5d3SJohn Marino start_time = get_usecs(&myts);
91386d7f5d3SJohn Marino if (!trywait_sem(&s->stop))
91486d7f5d3SJohn Marino goto out;
91586d7f5d3SJohn Marino if (tk->sleep_interval) {
91686d7f5d3SJohn Marino unsigned long diff = 0;
91786d7f5d3SJohn Marino microsleep(tk->sleep_interval);
91886d7f5d3SJohn Marino now = get_usecs(&myts);
91986d7f5d3SJohn Marino /* now should always be > start_time but... */
92086d7f5d3SJohn Marino if (now > start_time) {
92186d7f5d3SJohn Marino diff = now - start_time;
92286d7f5d3SJohn Marino if (diff > tk->sleep_interval)
92386d7f5d3SJohn Marino tk->slept_interval = diff -
92486d7f5d3SJohn Marino tk->sleep_interval;
92586d7f5d3SJohn Marino }
92686d7f5d3SJohn Marino }
92786d7f5d3SJohn Marino tk->sleep_interval = 0;
92886d7f5d3SJohn Marino post_sem(&s->complete);
92986d7f5d3SJohn Marino }
93086d7f5d3SJohn Marino out:
93186d7f5d3SJohn Marino return NULL;
93286d7f5d3SJohn Marino }
93386d7f5d3SJohn Marino
93486d7f5d3SJohn Marino /*
93586d7f5d3SJohn Marino * All the sleep functions such as nanosleep can only guarantee that they
93686d7f5d3SJohn Marino * sleep for _at least_ the time requested. We work around this by having
93786d7f5d3SJohn Marino * a high priority real time thread that accounts for the extra time slept
93886d7f5d3SJohn Marino * in nanosleep. This allows wakeup latency of the tested thread to be
93986d7f5d3SJohn Marino * accurate and reflect true scheduling delays.
94086d7f5d3SJohn Marino */
emulation_thread(void * t)94186d7f5d3SJohn Marino void *emulation_thread(void *t)
94286d7f5d3SJohn Marino {
94386d7f5d3SJohn Marino struct thread *th;
94486d7f5d3SJohn Marino struct tk_thread *tk;
94586d7f5d3SJohn Marino struct sems *s, *tks;
94686d7f5d3SJohn Marino long i = (long)t;
94786d7f5d3SJohn Marino
94886d7f5d3SJohn Marino th = &threadlist[i];
94986d7f5d3SJohn Marino tk = &th->tkthread;
95086d7f5d3SJohn Marino s = &th->sem;
95186d7f5d3SJohn Marino tks = &tk->sem;
95286d7f5d3SJohn Marino init_all_sems(tks);
95386d7f5d3SJohn Marino
95486d7f5d3SJohn Marino /* Start the timekeeping thread */
95586d7f5d3SJohn Marino create_pthread(&th->tk_pthread, NULL, timekeeping_thread,
95686d7f5d3SJohn Marino (void*)(long) i);
95786d7f5d3SJohn Marino /* Wait for timekeeping thread to be ready */
95886d7f5d3SJohn Marino wait_sem(&tks->ready);
95986d7f5d3SJohn Marino
96086d7f5d3SJohn Marino /* Tell main we're ready to start*/
96186d7f5d3SJohn Marino post_sem(&s->ready);
96286d7f5d3SJohn Marino
96386d7f5d3SJohn Marino /* Wait for signal from main to start thread */
96486d7f5d3SJohn Marino wait_sem(&s->start);
96586d7f5d3SJohn Marino
96686d7f5d3SJohn Marino /* Start the actual function being benched/or running as load */
96786d7f5d3SJohn Marino th->name(th);
96886d7f5d3SJohn Marino
96986d7f5d3SJohn Marino /* Stop the timekeeping thread */
97086d7f5d3SJohn Marino post_sem(&tks->stop);
97186d7f5d3SJohn Marino post_sem(&tks->start);
97286d7f5d3SJohn Marino join_pthread(th->tk_pthread, NULL);
97386d7f5d3SJohn Marino
97486d7f5d3SJohn Marino /* Tell main we've finished */
97586d7f5d3SJohn Marino post_sem(&s->complete);
97686d7f5d3SJohn Marino return NULL;
97786d7f5d3SJohn Marino }
97886d7f5d3SJohn Marino
97986d7f5d3SJohn Marino /*
98086d7f5d3SJohn Marino * In an unoptimised loop we try to benchmark how many meaningless loops
98186d7f5d3SJohn Marino * per second we can perform on this hardware to fairly accurately
98286d7f5d3SJohn Marino * reproduce certain percentage cpu usage
98386d7f5d3SJohn Marino */
calibrate_loop(void)98486d7f5d3SJohn Marino void calibrate_loop(void)
98586d7f5d3SJohn Marino {
98686d7f5d3SJohn Marino unsigned long long start_time, loops_per_msec, run_time = 0;
98786d7f5d3SJohn Marino unsigned long loops;
98886d7f5d3SJohn Marino struct timespec myts;
98986d7f5d3SJohn Marino
99086d7f5d3SJohn Marino loops_per_msec = 100000;
99186d7f5d3SJohn Marino redo:
99286d7f5d3SJohn Marino /* Calibrate to within 1% accuracy */
99386d7f5d3SJohn Marino while (run_time > 1010000 || run_time < 990000) {
99486d7f5d3SJohn Marino loops = loops_per_msec;
99586d7f5d3SJohn Marino start_time = get_nsecs(&myts);
99686d7f5d3SJohn Marino burn_loops(loops);
99786d7f5d3SJohn Marino run_time = get_nsecs(&myts) - start_time;
99886d7f5d3SJohn Marino loops_per_msec = (1000000 * loops_per_msec / run_time ? :
99986d7f5d3SJohn Marino loops_per_msec);
100086d7f5d3SJohn Marino }
100186d7f5d3SJohn Marino
100286d7f5d3SJohn Marino /* Rechecking after a pause increases reproducibility */
100386d7f5d3SJohn Marino sleep(1);
100486d7f5d3SJohn Marino loops = loops_per_msec;
100586d7f5d3SJohn Marino start_time = get_nsecs(&myts);
100686d7f5d3SJohn Marino burn_loops(loops);
100786d7f5d3SJohn Marino run_time = get_nsecs(&myts) - start_time;
100886d7f5d3SJohn Marino
100986d7f5d3SJohn Marino /* Tolerate 5% difference on checking */
101086d7f5d3SJohn Marino if (run_time > 1050000 || run_time < 950000)
101186d7f5d3SJohn Marino goto redo;
101286d7f5d3SJohn Marino
101386d7f5d3SJohn Marino ud.loops_per_ms = loops_per_msec;
101486d7f5d3SJohn Marino }
101586d7f5d3SJohn Marino
101686d7f5d3SJohn Marino void log_output(const char *format, ...) __attribute__ ((format(printf, 1, 2)));
101786d7f5d3SJohn Marino
101886d7f5d3SJohn Marino /* Output to console +/- logfile */
log_output(const char * format,...)101986d7f5d3SJohn Marino void log_output(const char *format, ...)
102086d7f5d3SJohn Marino {
102186d7f5d3SJohn Marino va_list ap;
102286d7f5d3SJohn Marino
102386d7f5d3SJohn Marino va_start(ap, format);
102486d7f5d3SJohn Marino if (vprintf(format, ap) == -1)
102586d7f5d3SJohn Marino terminal_error("vprintf");
102686d7f5d3SJohn Marino va_end(ap);
102786d7f5d3SJohn Marino if (ud.log) {
102886d7f5d3SJohn Marino va_start(ap, format);
102986d7f5d3SJohn Marino if (vfprintf(ud.logfile, format, ap) == -1)
103086d7f5d3SJohn Marino terminal_error("vpfrintf");
103186d7f5d3SJohn Marino va_end(ap);
103286d7f5d3SJohn Marino }
103386d7f5d3SJohn Marino fflush(NULL);
103486d7f5d3SJohn Marino }
103586d7f5d3SJohn Marino
103686d7f5d3SJohn Marino /* Calculate statistics and output them */
show_latencies(struct thread * th)103786d7f5d3SJohn Marino void show_latencies(struct thread *th)
103886d7f5d3SJohn Marino {
103986d7f5d3SJohn Marino struct data_table *tbj;
104086d7f5d3SJohn Marino struct tk_thread *tk;
104186d7f5d3SJohn Marino double average_latency, deadlines_met, samples_met, sd, max_latency;
104286d7f5d3SJohn Marino long double variance = 0;
104386d7f5d3SJohn Marino
104486d7f5d3SJohn Marino tbj = th->dt;
104586d7f5d3SJohn Marino tk = &th->tkthread;
104686d7f5d3SJohn Marino
104786d7f5d3SJohn Marino if (tbj->nr_samples > 1) {
104886d7f5d3SJohn Marino average_latency = tbj->total_latency / tbj->nr_samples;
104986d7f5d3SJohn Marino variance = (tbj->sum_latency_squared - (average_latency *
105086d7f5d3SJohn Marino average_latency) / tbj->nr_samples) / (tbj->nr_samples - 1);
105186d7f5d3SJohn Marino sd = sqrt((double)variance);
105286d7f5d3SJohn Marino } else {
105386d7f5d3SJohn Marino average_latency = tbj->total_latency;
105486d7f5d3SJohn Marino sd = 0.0;
105586d7f5d3SJohn Marino }
105686d7f5d3SJohn Marino
105786d7f5d3SJohn Marino /*
105886d7f5d3SJohn Marino * Landing on the boundary of a deadline can make loaded runs appear
105986d7f5d3SJohn Marino * to do more work than unloaded due to tiny duration differences.
106086d7f5d3SJohn Marino */
106186d7f5d3SJohn Marino if (tbj->achieved_burns > 0)
106286d7f5d3SJohn Marino samples_met = (double)tbj->achieved_burns /
106386d7f5d3SJohn Marino (double)(tbj->achieved_burns + tbj->missed_burns) * 100;
106486d7f5d3SJohn Marino else
106586d7f5d3SJohn Marino samples_met = 0.0;
106686d7f5d3SJohn Marino max_latency = tbj->max_latency;
106786d7f5d3SJohn Marino /* When benchmarking rt we represent the data in us */
106886d7f5d3SJohn Marino if (!ud.do_rt) {
106986d7f5d3SJohn Marino average_latency /= 1000;
107086d7f5d3SJohn Marino sd /= 1000;
107186d7f5d3SJohn Marino max_latency /= 1000;
107286d7f5d3SJohn Marino }
107386d7f5d3SJohn Marino if (tbj->deadlines_met == 0)
107486d7f5d3SJohn Marino deadlines_met = 0;
107586d7f5d3SJohn Marino else
107686d7f5d3SJohn Marino deadlines_met = (double)tbj->deadlines_met /
107786d7f5d3SJohn Marino (double)(tbj->missed_deadlines + tbj->deadlines_met) * 100;
107886d7f5d3SJohn Marino
107986d7f5d3SJohn Marino /* Messy nonsense to format the output nicely */
108086d7f5d3SJohn Marino if (average_latency >= 100)
108186d7f5d3SJohn Marino log_output("%7.0f +/- ", average_latency);
108286d7f5d3SJohn Marino else
108386d7f5d3SJohn Marino log_output("%7.3g +/- ", average_latency);
108486d7f5d3SJohn Marino if (sd >= 100)
108586d7f5d3SJohn Marino log_output("%-9.0f", sd);
108686d7f5d3SJohn Marino else
108786d7f5d3SJohn Marino log_output("%-9.3g", sd);
108886d7f5d3SJohn Marino if (max_latency >= 100)
108986d7f5d3SJohn Marino log_output("%7.0f\t", max_latency);
109086d7f5d3SJohn Marino else
109186d7f5d3SJohn Marino log_output("%7.3g\t", max_latency);
109286d7f5d3SJohn Marino log_output("\t%4.3g", samples_met);
109386d7f5d3SJohn Marino if (!th->nodeadlines)
109486d7f5d3SJohn Marino log_output("\t%11.3g", deadlines_met);
109586d7f5d3SJohn Marino log_output("\n");
109686d7f5d3SJohn Marino sync_flush();
109786d7f5d3SJohn Marino }
109886d7f5d3SJohn Marino
create_read_file(void)109986d7f5d3SJohn Marino void create_read_file(void)
110086d7f5d3SJohn Marino {
110186d7f5d3SJohn Marino unsigned int i;
110286d7f5d3SJohn Marino FILE *fp;
110386d7f5d3SJohn Marino char *name = "interbench.read";
110486d7f5d3SJohn Marino void *buf = NULL;
110586d7f5d3SJohn Marino struct stat statbuf;
110686d7f5d3SJohn Marino unsigned long mem, bsize;
110786d7f5d3SJohn Marino int tmp;
110886d7f5d3SJohn Marino
110986d7f5d3SJohn Marino if ((tmp = open(name, O_RDONLY)) == -1) {
111086d7f5d3SJohn Marino if (errno != ENOENT)
111186d7f5d3SJohn Marino terminal_error("open");
111286d7f5d3SJohn Marino goto write;
111386d7f5d3SJohn Marino }
111486d7f5d3SJohn Marino if (stat(name, &statbuf) == -1)
111586d7f5d3SJohn Marino terminal_error("stat");
111686d7f5d3SJohn Marino if (statbuf.st_blksize < MIN_BLK_SIZE)
111786d7f5d3SJohn Marino statbuf.st_blksize = MIN_BLK_SIZE;
111886d7f5d3SJohn Marino bsize = statbuf.st_blksize;
111986d7f5d3SJohn Marino if (statbuf.st_size / 1024 / bsize == ud.ram / bsize)
112086d7f5d3SJohn Marino return;
112186d7f5d3SJohn Marino if (remove(name) == -1)
112286d7f5d3SJohn Marino terminal_error("remove");
112386d7f5d3SJohn Marino write:
112486d7f5d3SJohn Marino fprintf(stderr,"Creating file for read load...\n");
112586d7f5d3SJohn Marino if (!(fp = fopen(name, "w")))
112686d7f5d3SJohn Marino terminal_error("fopen");
112786d7f5d3SJohn Marino if (stat(name, &statbuf) == -1)
112886d7f5d3SJohn Marino terminal_fileopen_error(fp, "stat");
112986d7f5d3SJohn Marino if (statbuf.st_blksize < MIN_BLK_SIZE)
113086d7f5d3SJohn Marino statbuf.st_blksize = MIN_BLK_SIZE;
113186d7f5d3SJohn Marino bsize = statbuf.st_blksize;
113286d7f5d3SJohn Marino if (!(buf = calloc(1, bsize)))
113386d7f5d3SJohn Marino terminal_fileopen_error(fp, "calloc");
113486d7f5d3SJohn Marino mem = ud.ram / (bsize / 1024); /* kilobytes to blocks */
113586d7f5d3SJohn Marino
113686d7f5d3SJohn Marino for (i = 0 ; i < mem; i++) {
113786d7f5d3SJohn Marino if (fwrite(buf, bsize, 1, fp) != 1)
113886d7f5d3SJohn Marino terminal_fileopen_error(fp, "fwrite");
113986d7f5d3SJohn Marino }
114086d7f5d3SJohn Marino if (fclose(fp) == -1)
114186d7f5d3SJohn Marino terminal_error("fclose");
114286d7f5d3SJohn Marino sync_flush();
114386d7f5d3SJohn Marino }
114486d7f5d3SJohn Marino
get_ram(void)114586d7f5d3SJohn Marino void get_ram(void)
114686d7f5d3SJohn Marino {
114786d7f5d3SJohn Marino struct vmstats vms;
114886d7f5d3SJohn Marino size_t vms_size = sizeof(vms);
114986d7f5d3SJohn Marino
115086d7f5d3SJohn Marino if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0))
115186d7f5d3SJohn Marino terminal_error("sysctlbyname: vm.vmstats");
115286d7f5d3SJohn Marino
115386d7f5d3SJohn Marino ud.ram = vms.v_page_count * vms.v_page_size;
115486d7f5d3SJohn Marino ud.ram /= 1024; /* linux size is in kB */
115586d7f5d3SJohn Marino ud.swap = ud.ram; /* XXX: swap doesn't have to be the same as RAM */
115686d7f5d3SJohn Marino
115786d7f5d3SJohn Marino if( !ud.ram || !ud.swap ) {
115886d7f5d3SJohn Marino unsigned long i;
115986d7f5d3SJohn Marino fprintf(stderr, "\nCould not get memory or swap size. ");
116086d7f5d3SJohn Marino fprintf(stderr, "Will not perform mem_load\n");
116186d7f5d3SJohn Marino for (i = 0 ; i < THREADS ; i++) {
116286d7f5d3SJohn Marino if (strcmp(threadlist[i].label, "Memload") == 0) {
116386d7f5d3SJohn Marino threadlist[i].load = 0;
116486d7f5d3SJohn Marino threadlist[i].rtload = 0;
116586d7f5d3SJohn Marino }
116686d7f5d3SJohn Marino }
116786d7f5d3SJohn Marino }
116886d7f5d3SJohn Marino }
116986d7f5d3SJohn Marino
get_logfilename(void)117086d7f5d3SJohn Marino void get_logfilename(void)
117186d7f5d3SJohn Marino {
117286d7f5d3SJohn Marino struct tm *mytm;
117386d7f5d3SJohn Marino struct utsname buf;
117486d7f5d3SJohn Marino time_t t;
117586d7f5d3SJohn Marino int year, month, day, hours, minutes;
117686d7f5d3SJohn Marino
117786d7f5d3SJohn Marino time(&t);
117886d7f5d3SJohn Marino if (uname(&buf) == -1)
117986d7f5d3SJohn Marino terminal_error("uname");
118086d7f5d3SJohn Marino if (!(mytm = localtime(&t)))
118186d7f5d3SJohn Marino terminal_error("localtime");
118286d7f5d3SJohn Marino year = mytm->tm_year + 1900;
118386d7f5d3SJohn Marino month = mytm->tm_mon + 1;
118486d7f5d3SJohn Marino day = mytm->tm_mday;
118586d7f5d3SJohn Marino hours = mytm->tm_hour;
118686d7f5d3SJohn Marino minutes = mytm->tm_min;
118786d7f5d3SJohn Marino strncpy(ud.unamer, buf.release, MAX_UNAME_LENGTH);
118886d7f5d3SJohn Marino
118986d7f5d3SJohn Marino sprintf(ud.datestamp, "%2d%02d%02d%02d%02d",
119086d7f5d3SJohn Marino year, month, day, hours, minutes);
119186d7f5d3SJohn Marino snprintf(ud.logfilename, MAX_LOG_LENGTH, "%s.log", ud.unamer);
119286d7f5d3SJohn Marino }
119386d7f5d3SJohn Marino
start_thread(struct thread * th)119486d7f5d3SJohn Marino void start_thread(struct thread *th)
119586d7f5d3SJohn Marino {
119686d7f5d3SJohn Marino post_sem(&th->sem.start);
119786d7f5d3SJohn Marino }
119886d7f5d3SJohn Marino
stop_thread(struct thread * th)119986d7f5d3SJohn Marino void stop_thread(struct thread *th)
120086d7f5d3SJohn Marino {
120186d7f5d3SJohn Marino post_sem(&th->sem.stop);
120286d7f5d3SJohn Marino wait_sem(&th->sem.complete);
120386d7f5d3SJohn Marino
120486d7f5d3SJohn Marino /* Kill the thread */
120586d7f5d3SJohn Marino join_pthread(th->pthread, NULL);
120686d7f5d3SJohn Marino }
120786d7f5d3SJohn Marino
init_sem(sem_t * sem)120886d7f5d3SJohn Marino void init_sem(sem_t *sem)
120986d7f5d3SJohn Marino {
121086d7f5d3SJohn Marino if (sem_init(sem, 0, 0))
121186d7f5d3SJohn Marino terminal_error("sem_init");
121286d7f5d3SJohn Marino }
121386d7f5d3SJohn Marino
init_all_sems(struct sems * s)121486d7f5d3SJohn Marino void init_all_sems(struct sems *s)
121586d7f5d3SJohn Marino {
121686d7f5d3SJohn Marino /* Initialise the semaphores */
121786d7f5d3SJohn Marino init_sem(&s->ready);
121886d7f5d3SJohn Marino init_sem(&s->start);
121986d7f5d3SJohn Marino init_sem(&s->stop);
122086d7f5d3SJohn Marino init_sem(&s->complete);
122186d7f5d3SJohn Marino init_sem(&s->stopchild);
122286d7f5d3SJohn Marino }
122386d7f5d3SJohn Marino
initialise_thread(int i)122486d7f5d3SJohn Marino void initialise_thread(int i)
122586d7f5d3SJohn Marino {
122686d7f5d3SJohn Marino struct thread *th = &threadlist[i];
122786d7f5d3SJohn Marino
122886d7f5d3SJohn Marino init_all_sems(&th->sem);
122986d7f5d3SJohn Marino /* Create the threads. Yes, the (long) cast is fugly but it's safe*/
123086d7f5d3SJohn Marino create_pthread(&th->pthread, NULL, emulation_thread, (void*)(long)i);
123186d7f5d3SJohn Marino
123286d7f5d3SJohn Marino wait_sem(&th->sem.ready);
123386d7f5d3SJohn Marino /*
123486d7f5d3SJohn Marino * We set this pointer generically to NOT_BENCHING and set it to the
123586d7f5d3SJohn Marino * benchmarked array entry only on benched threads.
123686d7f5d3SJohn Marino */
123786d7f5d3SJohn Marino th->dt = &th->benchmarks[NOT_BENCHING];
123886d7f5d3SJohn Marino initialise_thread_data(th->dt);
123986d7f5d3SJohn Marino
124086d7f5d3SJohn Marino }
124186d7f5d3SJohn Marino
124286d7f5d3SJohn Marino /* A pseudo-semaphore for processes using a pipe */
wait_on(int pype)124386d7f5d3SJohn Marino void wait_on(int pype)
124486d7f5d3SJohn Marino {
124586d7f5d3SJohn Marino int retval, buf = 0;
124686d7f5d3SJohn Marino
124786d7f5d3SJohn Marino retval = Read(pype, &buf, sizeof(buf));
124886d7f5d3SJohn Marino if (retval == 0) {
124986d7f5d3SJohn Marino fprintf(stderr, "\nread returned 0\n");
125086d7f5d3SJohn Marino exit (1);
125186d7f5d3SJohn Marino }
125286d7f5d3SJohn Marino }
125386d7f5d3SJohn Marino
wakeup_with(int pype)125486d7f5d3SJohn Marino void wakeup_with(int pype)
125586d7f5d3SJohn Marino {
125686d7f5d3SJohn Marino int retval, buf = 1;
125786d7f5d3SJohn Marino
125886d7f5d3SJohn Marino retval = Write(pype, &buf, sizeof(buf));
125986d7f5d3SJohn Marino if (retval == 0) {
126086d7f5d3SJohn Marino fprintf(stderr, "\nwrite returned 0\n");
126186d7f5d3SJohn Marino exit (1);
126286d7f5d3SJohn Marino }
126386d7f5d3SJohn Marino }
126486d7f5d3SJohn Marino
run_loadchild(int j)126586d7f5d3SJohn Marino void run_loadchild(int j)
126686d7f5d3SJohn Marino {
126786d7f5d3SJohn Marino struct thread *thj;
126886d7f5d3SJohn Marino thj = &threadlist[j];
126986d7f5d3SJohn Marino
127086d7f5d3SJohn Marino set_nice(ud.load_nice);
127186d7f5d3SJohn Marino initialise_thread(j);
127286d7f5d3SJohn Marino
127386d7f5d3SJohn Marino /* Tell main we're ready */
127486d7f5d3SJohn Marino wakeup_with(l2m[1]);
127586d7f5d3SJohn Marino
127686d7f5d3SJohn Marino /* Main tells us we're ready */
127786d7f5d3SJohn Marino wait_on(m2l[0]);
127886d7f5d3SJohn Marino start_thread(thj);
127986d7f5d3SJohn Marino
128086d7f5d3SJohn Marino /* Tell main we received the start and are running */
128186d7f5d3SJohn Marino wakeup_with(l2m[1]);
128286d7f5d3SJohn Marino
128386d7f5d3SJohn Marino /* Main tells us to stop */
128486d7f5d3SJohn Marino wait_on(m2l[0]);
128586d7f5d3SJohn Marino stop_thread(thj);
128686d7f5d3SJohn Marino
128786d7f5d3SJohn Marino /* Tell main we've finished */
128886d7f5d3SJohn Marino wakeup_with(l2m[1]);
128986d7f5d3SJohn Marino exit (0);
129086d7f5d3SJohn Marino }
129186d7f5d3SJohn Marino
run_benchchild(int i,int j)129286d7f5d3SJohn Marino void run_benchchild(int i, int j)
129386d7f5d3SJohn Marino {
129486d7f5d3SJohn Marino struct thread *thi;
129586d7f5d3SJohn Marino
129686d7f5d3SJohn Marino thi = &threadlist[i];
129786d7f5d3SJohn Marino
129886d7f5d3SJohn Marino set_nice(ud.bench_nice);
129986d7f5d3SJohn Marino if (ud.do_rt)
130086d7f5d3SJohn Marino set_mlock();
130186d7f5d3SJohn Marino initialise_thread(i);
130286d7f5d3SJohn Marino /* Point the data table to the appropriate load being tested */
130386d7f5d3SJohn Marino thi->dt = &thi->benchmarks[j];
130486d7f5d3SJohn Marino initialise_thread_data(thi->dt);
130586d7f5d3SJohn Marino if (ud.do_rt)
130686d7f5d3SJohn Marino set_thread_fifo(thi->pthread, 95);
130786d7f5d3SJohn Marino
130886d7f5d3SJohn Marino /* Tell main we're ready */
130986d7f5d3SJohn Marino wakeup_with(b2m[1]);
131086d7f5d3SJohn Marino
131186d7f5d3SJohn Marino /* Main tells us we're ready */
131286d7f5d3SJohn Marino wait_on(m2b[0]);
131386d7f5d3SJohn Marino start_thread(thi);
131486d7f5d3SJohn Marino
131586d7f5d3SJohn Marino /* Tell main we have started */
131686d7f5d3SJohn Marino wakeup_with(b2m[1]);
131786d7f5d3SJohn Marino
131886d7f5d3SJohn Marino /* Main tells us to stop */
131986d7f5d3SJohn Marino wait_on(m2b[0]);
132086d7f5d3SJohn Marino stop_thread(thi);
132186d7f5d3SJohn Marino
132286d7f5d3SJohn Marino if (ud.do_rt) {
132386d7f5d3SJohn Marino set_thread_normal(thi->pthread);
132486d7f5d3SJohn Marino set_munlock();
132586d7f5d3SJohn Marino }
132686d7f5d3SJohn Marino show_latencies(thi);
132786d7f5d3SJohn Marino
132886d7f5d3SJohn Marino /* Tell main we've finished */
132986d7f5d3SJohn Marino wakeup_with(b2m[1]);
133086d7f5d3SJohn Marino exit(0);
133186d7f5d3SJohn Marino }
133286d7f5d3SJohn Marino
bench(int i,int j)133386d7f5d3SJohn Marino void bench(int i, int j)
133486d7f5d3SJohn Marino {
133586d7f5d3SJohn Marino pid_t bench_pid, load_pid;
133686d7f5d3SJohn Marino
133786d7f5d3SJohn Marino if ((load_pid = fork()) == -1)
133886d7f5d3SJohn Marino terminal_error("fork");
133986d7f5d3SJohn Marino if (!load_pid)
134086d7f5d3SJohn Marino run_loadchild(j);
134186d7f5d3SJohn Marino
134286d7f5d3SJohn Marino /* Wait for load process to be ready */
134386d7f5d3SJohn Marino
134486d7f5d3SJohn Marino wait_on(l2m[0]);
134586d7f5d3SJohn Marino if ((bench_pid = fork()) == -1)
134686d7f5d3SJohn Marino terminal_error("fork");
134786d7f5d3SJohn Marino if (!bench_pid)
134886d7f5d3SJohn Marino run_benchchild(i, j);
134986d7f5d3SJohn Marino
135086d7f5d3SJohn Marino /* Wait for bench process to be ready */
135186d7f5d3SJohn Marino wait_on(b2m[0]);
135286d7f5d3SJohn Marino
135386d7f5d3SJohn Marino /*
135486d7f5d3SJohn Marino * We want to be higher priority than everything to signal them to
135586d7f5d3SJohn Marino * stop and we lock our memory if we can as well
135686d7f5d3SJohn Marino */
135786d7f5d3SJohn Marino set_fifo(99);
135886d7f5d3SJohn Marino set_mlock();
135986d7f5d3SJohn Marino
136086d7f5d3SJohn Marino /* Wakeup the load process */
136186d7f5d3SJohn Marino wakeup_with(m2l[1]);
136286d7f5d3SJohn Marino /* Load tells it has received the first message and is running */
136386d7f5d3SJohn Marino wait_on(l2m[0]);
136486d7f5d3SJohn Marino
136586d7f5d3SJohn Marino /* After a small delay, wake up the benched process */
136686d7f5d3SJohn Marino sleep(1);
136786d7f5d3SJohn Marino wakeup_with(m2b[1]);
136886d7f5d3SJohn Marino
136986d7f5d3SJohn Marino /* Bench tells it has received the first message and is running */
137086d7f5d3SJohn Marino wait_on(b2m[0]);
137186d7f5d3SJohn Marino microsleep(ud.duration * 1000000);
137286d7f5d3SJohn Marino
137386d7f5d3SJohn Marino /* Tell the benched process to stop its threads and output results */
137486d7f5d3SJohn Marino wakeup_with(m2b[1]);
137586d7f5d3SJohn Marino
137686d7f5d3SJohn Marino /* Tell the load process to stop its threads */
137786d7f5d3SJohn Marino wakeup_with(m2l[1]);
137886d7f5d3SJohn Marino
137986d7f5d3SJohn Marino /* Return to SCHED_NORMAL */
138086d7f5d3SJohn Marino set_normal();
138186d7f5d3SJohn Marino set_munlock();
138286d7f5d3SJohn Marino
138386d7f5d3SJohn Marino /* Wait for load and bench processes to terminate */
138486d7f5d3SJohn Marino wait_on(l2m[0]);
138586d7f5d3SJohn Marino wait_on(b2m[0]);
138686d7f5d3SJohn Marino }
138786d7f5d3SJohn Marino
init_pipe(int * pype)138886d7f5d3SJohn Marino void init_pipe(int *pype)
138986d7f5d3SJohn Marino {
139086d7f5d3SJohn Marino if (pipe(pype) == -1)
139186d7f5d3SJohn Marino terminal_error("pipe");
139286d7f5d3SJohn Marino }
139386d7f5d3SJohn Marino
init_pipes(void)139486d7f5d3SJohn Marino void init_pipes(void)
139586d7f5d3SJohn Marino {
139686d7f5d3SJohn Marino init_pipe(m2l);
139786d7f5d3SJohn Marino init_pipe(l2m);
139886d7f5d3SJohn Marino init_pipe(m2b);
139986d7f5d3SJohn Marino init_pipe(b2m);
140086d7f5d3SJohn Marino }
140186d7f5d3SJohn Marino
usage(void)140286d7f5d3SJohn Marino void usage(void)
140386d7f5d3SJohn Marino {
140486d7f5d3SJohn Marino /* Affinity commented out till working on all architectures */
140586d7f5d3SJohn Marino fprintf(stderr, "interbench v " INTERBENCH_VERSION " by Con Kolivas\n");
140686d7f5d3SJohn Marino fprintf(stderr, "interbench [-l <int>] [-L <int>] [-t <int] [-B <int>] [-N <int>]\n");
140786d7f5d3SJohn Marino fprintf(stderr, "\t[-b] [-c] [-r] [-C <int> -I <int>] [-m <comment>]\n");
140886d7f5d3SJohn Marino fprintf(stderr, "\t[-w <load type>] [-x <load type>] [-W <bench>] [-X <bench>]\n");
140986d7f5d3SJohn Marino fprintf(stderr, "\t[-h]\n\n");
141086d7f5d3SJohn Marino fprintf(stderr, " -l\tUse <int> loops per sec (default: use saved benchmark)\n");
141186d7f5d3SJohn Marino fprintf(stderr, " -L\tUse cpu load of <int> with burn load (default: 4)\n");
141286d7f5d3SJohn Marino fprintf(stderr, " -t\tSeconds to run each benchmark (default: 30)\n");
141386d7f5d3SJohn Marino fprintf(stderr, " -B\tNice the benchmarked thread to <int> (default: 0)\n");
141486d7f5d3SJohn Marino fprintf(stderr, " -N\tNice the load thread to <int> (default: 0)\n");
141586d7f5d3SJohn Marino //fprintf(stderr, " -u\tImitate uniprocessor\n");
141686d7f5d3SJohn Marino fprintf(stderr, " -b\tBenchmark loops_per_ms even if it is already known\n");
141786d7f5d3SJohn Marino fprintf(stderr, " -c\tOutput to console only (default: use console and logfile)\n");
141886d7f5d3SJohn Marino fprintf(stderr, " -r\tPerform real time scheduling benchmarks (default: non-rt)\n");
141986d7f5d3SJohn Marino fprintf(stderr, " -C\tUse <int> percentage cpu as a custom load (default: no custom load)\n");
142086d7f5d3SJohn Marino fprintf(stderr, " -I\tUse <int> microsecond intervals for custom load (needs -C as well)\n");
142186d7f5d3SJohn Marino fprintf(stderr, " -m\tAdd <comment> to the log file as a separate line\n");
142286d7f5d3SJohn Marino fprintf(stderr, " -w\tAdd <load type> to the list of loads to be tested against\n");
142386d7f5d3SJohn Marino fprintf(stderr, " -x\tExclude <load type> from the list of loads to be tested against\n");
142486d7f5d3SJohn Marino fprintf(stderr, " -W\tAdd <bench> to the list of benchmarks to be tested\n");
142586d7f5d3SJohn Marino fprintf(stderr, " -X\tExclude <bench> from the list of benchmarks to be tested\n");
142686d7f5d3SJohn Marino fprintf(stderr, " -h\tShow this help\n");
142786d7f5d3SJohn Marino fprintf(stderr, "\nIf run without parameters interbench will run a standard benchmark\n\n");
142886d7f5d3SJohn Marino }
142986d7f5d3SJohn Marino
143086d7f5d3SJohn Marino #ifdef DEBUG
deadchild(int crap)143186d7f5d3SJohn Marino void deadchild(int crap)
143286d7f5d3SJohn Marino {
143386d7f5d3SJohn Marino pid_t retval;
143486d7f5d3SJohn Marino int status;
143586d7f5d3SJohn Marino
143686d7f5d3SJohn Marino crap = 0;
143786d7f5d3SJohn Marino
143886d7f5d3SJohn Marino if ((retval = waitpid(-1, &status, WNOHANG)) == -1) {
143986d7f5d3SJohn Marino if (errno == ECHILD)
144086d7f5d3SJohn Marino return;
144186d7f5d3SJohn Marino terminal_error("waitpid");
144286d7f5d3SJohn Marino }
144386d7f5d3SJohn Marino if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
144486d7f5d3SJohn Marino return;
144586d7f5d3SJohn Marino fprintf(stderr, "\nChild terminated abnormally ");
144686d7f5d3SJohn Marino if (WIFSIGNALED(status))
144786d7f5d3SJohn Marino fprintf(stderr, "with signal %d", WTERMSIG(status));
144886d7f5d3SJohn Marino fprintf(stderr, "\n");
144986d7f5d3SJohn Marino exit (1);
145086d7f5d3SJohn Marino }
145186d7f5d3SJohn Marino #endif
145286d7f5d3SJohn Marino
load_index(const char * loadname)145386d7f5d3SJohn Marino int load_index(const char* loadname)
145486d7f5d3SJohn Marino {
145586d7f5d3SJohn Marino int i;
145686d7f5d3SJohn Marino
145786d7f5d3SJohn Marino for (i = 0 ; i < THREADS ; i++)
145886d7f5d3SJohn Marino if (strcasecmp(loadname, threadlist[i].label) == 0)
145986d7f5d3SJohn Marino return i;
146086d7f5d3SJohn Marino return -1;
146186d7f5d3SJohn Marino }
146286d7f5d3SJohn Marino
bit_is_on(const unsigned int mask,int index)146386d7f5d3SJohn Marino inline int bit_is_on(const unsigned int mask, int index)
146486d7f5d3SJohn Marino {
146586d7f5d3SJohn Marino return (mask & (1 << index)) != 0;
146686d7f5d3SJohn Marino }
146786d7f5d3SJohn Marino
set_bit_on(unsigned int * mask,int index)146886d7f5d3SJohn Marino inline void set_bit_on(unsigned int *mask, int index)
146986d7f5d3SJohn Marino {
147086d7f5d3SJohn Marino *mask |= (1 << index);
147186d7f5d3SJohn Marino }
147286d7f5d3SJohn Marino
main(int argc,char ** argv)147386d7f5d3SJohn Marino int main(int argc, char **argv)
147486d7f5d3SJohn Marino {
147586d7f5d3SJohn Marino unsigned long custom_cpu = 0;
147686d7f5d3SJohn Marino int q, i, j, affinity, benchmark = 0;
147786d7f5d3SJohn Marino unsigned int selected_loads = 0;
147886d7f5d3SJohn Marino unsigned int excluded_loads = 0;
147986d7f5d3SJohn Marino unsigned int selected_benches = 0;
148086d7f5d3SJohn Marino unsigned int excluded_benches = 0;
148186d7f5d3SJohn Marino FILE *fp;
148286d7f5d3SJohn Marino /*
148386d7f5d3SJohn Marino * This file stores the loops_per_ms to be reused in a filename that
148486d7f5d3SJohn Marino * can't be confused
148586d7f5d3SJohn Marino */
148686d7f5d3SJohn Marino char *fname = "interbench.loops_per_ms";
148786d7f5d3SJohn Marino char *comment = NULL;
148886d7f5d3SJohn Marino #ifdef DEBUG
148986d7f5d3SJohn Marino feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
149086d7f5d3SJohn Marino if (signal(SIGCHLD, deadchild) == SIG_ERR)
149186d7f5d3SJohn Marino terminal_error("signal");
149286d7f5d3SJohn Marino #endif
149386d7f5d3SJohn Marino
149486d7f5d3SJohn Marino while ((q = getopt(argc, argv, "hl:L:B:N:ut:bcnrC:I:m:w:x:W:X:")) != -1) {
149586d7f5d3SJohn Marino switch (q) {
149686d7f5d3SJohn Marino case 'h':
149786d7f5d3SJohn Marino usage();
149886d7f5d3SJohn Marino return (0);
149986d7f5d3SJohn Marino case 'l':
150086d7f5d3SJohn Marino ud.loops_per_ms = atoi(optarg);
150186d7f5d3SJohn Marino break;
150286d7f5d3SJohn Marino case 't':
150386d7f5d3SJohn Marino ud.duration = atoi(optarg);
150486d7f5d3SJohn Marino break;
150586d7f5d3SJohn Marino case 'L':
150686d7f5d3SJohn Marino ud.cpu_load = atoi(optarg);
150786d7f5d3SJohn Marino break;
150886d7f5d3SJohn Marino case 'B':
150986d7f5d3SJohn Marino ud.bench_nice = atoi(optarg);
151086d7f5d3SJohn Marino break;
151186d7f5d3SJohn Marino case 'N':
151286d7f5d3SJohn Marino ud.load_nice = atoi(optarg);
151386d7f5d3SJohn Marino break;
151486d7f5d3SJohn Marino case 'u':
151586d7f5d3SJohn Marino affinity = 1;
151686d7f5d3SJohn Marino break;
151786d7f5d3SJohn Marino case 'b':
151886d7f5d3SJohn Marino benchmark = 1;
151986d7f5d3SJohn Marino break;
152086d7f5d3SJohn Marino case 'c':
152186d7f5d3SJohn Marino ud.log = 0;
152286d7f5d3SJohn Marino break;
152386d7f5d3SJohn Marino case 'r':
152486d7f5d3SJohn Marino ud.do_rt = 1;
152586d7f5d3SJohn Marino break;
152686d7f5d3SJohn Marino case 'C':
152786d7f5d3SJohn Marino custom_cpu = (unsigned long)atol(optarg);
152886d7f5d3SJohn Marino break;
152986d7f5d3SJohn Marino case 'I':
153086d7f5d3SJohn Marino ud.custom_interval = atol(optarg);
153186d7f5d3SJohn Marino break;
153286d7f5d3SJohn Marino case 'm':
153386d7f5d3SJohn Marino comment = optarg;
153486d7f5d3SJohn Marino break;
153586d7f5d3SJohn Marino case 'w':
153686d7f5d3SJohn Marino i = load_index(optarg);
153786d7f5d3SJohn Marino if (i == -1) {
153886d7f5d3SJohn Marino fprintf(stderr, "Unknown load \"%s\"\n", optarg);
153986d7f5d3SJohn Marino return (-2);
154086d7f5d3SJohn Marino }
154186d7f5d3SJohn Marino set_bit_on(&selected_loads, i);
154286d7f5d3SJohn Marino break;
154386d7f5d3SJohn Marino case 'x':
154486d7f5d3SJohn Marino i = load_index(optarg);
154586d7f5d3SJohn Marino if (i == -1) {
154686d7f5d3SJohn Marino fprintf(stderr, "Unknown load \"%s\"\n", optarg);
154786d7f5d3SJohn Marino return (-2);
154886d7f5d3SJohn Marino }
154986d7f5d3SJohn Marino set_bit_on(&excluded_loads, i);
155086d7f5d3SJohn Marino break;
155186d7f5d3SJohn Marino case 'W':
155286d7f5d3SJohn Marino i = load_index(optarg);
155386d7f5d3SJohn Marino if (i == -1) {
155486d7f5d3SJohn Marino fprintf(stderr, "Unknown bench \"%s\"\n", optarg);
155586d7f5d3SJohn Marino return (-2);
155686d7f5d3SJohn Marino }
155786d7f5d3SJohn Marino set_bit_on(&selected_benches, i);
155886d7f5d3SJohn Marino break;
155986d7f5d3SJohn Marino case 'X':
156086d7f5d3SJohn Marino i = load_index(optarg);
156186d7f5d3SJohn Marino if (i == -1) {
156286d7f5d3SJohn Marino fprintf(stderr, "Unknown bench \"%s\"\n", optarg);
156386d7f5d3SJohn Marino return (-2);
156486d7f5d3SJohn Marino }
156586d7f5d3SJohn Marino set_bit_on(&excluded_benches, i);
156686d7f5d3SJohn Marino break;
156786d7f5d3SJohn Marino default:
156886d7f5d3SJohn Marino usage();
156986d7f5d3SJohn Marino return (1);
157086d7f5d3SJohn Marino }
157186d7f5d3SJohn Marino }
157286d7f5d3SJohn Marino argc -= optind;
157386d7f5d3SJohn Marino argv += optind;
157486d7f5d3SJohn Marino /* default is all loads */
157586d7f5d3SJohn Marino if (selected_loads == 0)
157686d7f5d3SJohn Marino selected_loads = (unsigned int)-1;
157786d7f5d3SJohn Marino selected_loads &= ~excluded_loads;
157886d7f5d3SJohn Marino /* default is all benches */
157986d7f5d3SJohn Marino if (selected_benches == 0)
158086d7f5d3SJohn Marino selected_benches = (unsigned int)-1;
158186d7f5d3SJohn Marino selected_benches &= ~excluded_benches;
158286d7f5d3SJohn Marino
158386d7f5d3SJohn Marino if (!test_fifo()) {
158486d7f5d3SJohn Marino fprintf(stderr, "Unable to get SCHED_FIFO (real time scheduling).\n");
158586d7f5d3SJohn Marino fprintf(stderr, "You either need to run this as root user or have support for real time RLIMITS.\n");
158686d7f5d3SJohn Marino if (ud.do_rt) {
158786d7f5d3SJohn Marino fprintf(stderr, "Real time tests were requested, aborting.\n");
158886d7f5d3SJohn Marino exit (1);
158986d7f5d3SJohn Marino }
159086d7f5d3SJohn Marino fprintf(stderr, "Results will be unreliable.\n");
159186d7f5d3SJohn Marino }
159286d7f5d3SJohn Marino if (!ud.cpu_load) {
159386d7f5d3SJohn Marino fprintf(stderr, "Invalid cpu load\n");
159486d7f5d3SJohn Marino exit (1);
159586d7f5d3SJohn Marino }
159686d7f5d3SJohn Marino
159786d7f5d3SJohn Marino if ((custom_cpu && !ud.custom_interval) ||
159886d7f5d3SJohn Marino (ud.custom_interval && !custom_cpu) ||
159986d7f5d3SJohn Marino custom_cpu > 100) {
160086d7f5d3SJohn Marino fprintf(stderr, "Invalid custom values, aborting.\n");
160186d7f5d3SJohn Marino exit (1);
160286d7f5d3SJohn Marino }
160386d7f5d3SJohn Marino
160486d7f5d3SJohn Marino if (custom_cpu && ud.custom_interval) {
160586d7f5d3SJohn Marino ud.custom_run = ud.custom_interval * custom_cpu / 100;
160686d7f5d3SJohn Marino threadlist[CUSTOM].bench = 1;
160786d7f5d3SJohn Marino threadlist[CUSTOM].load = 1;
160886d7f5d3SJohn Marino threadlist[CUSTOM].rtbench = 1;
160986d7f5d3SJohn Marino threadlist[CUSTOM].rtload = 1;
161086d7f5d3SJohn Marino }
161186d7f5d3SJohn Marino
161286d7f5d3SJohn Marino /*FIXME Affinity commented out till working on all architectures */
161386d7f5d3SJohn Marino #if 0
161486d7f5d3SJohn Marino if (affinity) {
161586d7f5d3SJohn Marino #ifdef CPU_SET /* Current glibc expects cpu_set_t */
161686d7f5d3SJohn Marino cpu_set_t cpumask;
161786d7f5d3SJohn Marino
161886d7f5d3SJohn Marino CPU_ZERO(&cpumask);
161986d7f5d3SJohn Marino CPU_SET(0, &cpumask);
162086d7f5d3SJohn Marino #else /* Old glibc expects unsigned long */
162186d7f5d3SJohn Marino unsigned long cpumask = 1;
162286d7f5d3SJohn Marino #endif
162386d7f5d3SJohn Marino if (sched_setaffinity(0, sizeof(cpumask), &cpumask) == -1) {
162486d7f5d3SJohn Marino if (errno != EPERM)
162586d7f5d3SJohn Marino terminal_error("sched_setaffinity");
162686d7f5d3SJohn Marino fprintf(stderr, "could not set cpu affinity\n");
162786d7f5d3SJohn Marino }
162886d7f5d3SJohn Marino }
162986d7f5d3SJohn Marino #endif
163086d7f5d3SJohn Marino
163186d7f5d3SJohn Marino /* Make benchmark a multiple of 10 seconds for proper range of X loads */
163286d7f5d3SJohn Marino if (ud.duration % 10)
163386d7f5d3SJohn Marino ud.duration += 10 - ud.duration % 10;
163486d7f5d3SJohn Marino
163586d7f5d3SJohn Marino if (benchmark)
163686d7f5d3SJohn Marino ud.loops_per_ms = 0;
163786d7f5d3SJohn Marino /*
163886d7f5d3SJohn Marino * Try to get loops_per_ms from command line first, file second, and
163986d7f5d3SJohn Marino * benchmark if not available.
164086d7f5d3SJohn Marino */
164186d7f5d3SJohn Marino if (!ud.loops_per_ms) {
164286d7f5d3SJohn Marino if (benchmark)
164386d7f5d3SJohn Marino goto bench;
164486d7f5d3SJohn Marino if ((fp = fopen(fname, "r"))) {
164586d7f5d3SJohn Marino fscanf(fp, "%lu", &ud.loops_per_ms);
164686d7f5d3SJohn Marino if (fclose(fp) == -1)
164786d7f5d3SJohn Marino terminal_error("fclose");
164886d7f5d3SJohn Marino if (ud.loops_per_ms) {
164986d7f5d3SJohn Marino fprintf(stderr,
165086d7f5d3SJohn Marino "%lu loops_per_ms read from file interbench.loops_per_ms\n",
165186d7f5d3SJohn Marino ud.loops_per_ms);
165286d7f5d3SJohn Marino goto loops_known;
165386d7f5d3SJohn Marino }
165486d7f5d3SJohn Marino } else
165586d7f5d3SJohn Marino if (errno != ENOENT)
165686d7f5d3SJohn Marino terminal_error("fopen");
165786d7f5d3SJohn Marino bench:
165886d7f5d3SJohn Marino fprintf(stderr, "loops_per_ms unknown; benchmarking...\n");
165986d7f5d3SJohn Marino
166086d7f5d3SJohn Marino /*
166186d7f5d3SJohn Marino * To get as accurate a loop as possible we time it running
166286d7f5d3SJohn Marino * SCHED_FIFO if we can
166386d7f5d3SJohn Marino */
166486d7f5d3SJohn Marino set_fifo(99);
166586d7f5d3SJohn Marino calibrate_loop();
166686d7f5d3SJohn Marino set_normal();
166786d7f5d3SJohn Marino } else
166886d7f5d3SJohn Marino fprintf(stderr, "loops_per_ms specified from command line\n");
166986d7f5d3SJohn Marino
167086d7f5d3SJohn Marino if (!(fp = fopen(fname, "w"))) {
167186d7f5d3SJohn Marino if (errno != EACCES) /* No write access is not terminal */
167286d7f5d3SJohn Marino terminal_error("fopen");
167386d7f5d3SJohn Marino fprintf(stderr, "Unable to write to file interbench.loops_per_ms\n");
167486d7f5d3SJohn Marino goto loops_known;
167586d7f5d3SJohn Marino }
167686d7f5d3SJohn Marino fprintf(fp, "%lu", ud.loops_per_ms);
167786d7f5d3SJohn Marino fprintf(stderr, "%lu loops_per_ms saved to file interbench.loops_per_ms\n",
167886d7f5d3SJohn Marino ud.loops_per_ms);
167986d7f5d3SJohn Marino if (fclose(fp) == -1)
168086d7f5d3SJohn Marino terminal_error("fclose");
168186d7f5d3SJohn Marino
168286d7f5d3SJohn Marino loops_known:
168386d7f5d3SJohn Marino get_ram();
168486d7f5d3SJohn Marino get_logfilename();
168586d7f5d3SJohn Marino create_read_file();
168686d7f5d3SJohn Marino init_pipes();
168786d7f5d3SJohn Marino
168886d7f5d3SJohn Marino if (ud.log && !(ud.logfile = fopen(ud.logfilename, "a"))) {
168986d7f5d3SJohn Marino if (errno != EACCES)
169086d7f5d3SJohn Marino terminal_error("fopen");
169186d7f5d3SJohn Marino fprintf(stderr, "Unable to write to logfile\n");
169286d7f5d3SJohn Marino ud.log = 0;
169386d7f5d3SJohn Marino }
169486d7f5d3SJohn Marino log_output("\n");
169586d7f5d3SJohn Marino log_output("Using %lu loops per ms, running every load for %d seconds\n",
169686d7f5d3SJohn Marino ud.loops_per_ms, ud.duration);
169786d7f5d3SJohn Marino log_output("Benchmarking kernel %s at datestamp %s\n",
169886d7f5d3SJohn Marino ud.unamer, ud.datestamp);
169986d7f5d3SJohn Marino if (comment)
170086d7f5d3SJohn Marino log_output("Comment: %s\n", comment);
170186d7f5d3SJohn Marino log_output("\n");
170286d7f5d3SJohn Marino
170386d7f5d3SJohn Marino for (i = 0 ; i < THREADS ; i++)
170486d7f5d3SJohn Marino threadlist[i].threadno = i;
170586d7f5d3SJohn Marino
170686d7f5d3SJohn Marino for (i = 0 ; i < THREADS ; i++) {
170786d7f5d3SJohn Marino struct thread *thi = &threadlist[i];
170886d7f5d3SJohn Marino int *benchme;
170986d7f5d3SJohn Marino
171086d7f5d3SJohn Marino if (ud.do_rt)
171186d7f5d3SJohn Marino benchme = &threadlist[i].rtbench;
171286d7f5d3SJohn Marino else
171386d7f5d3SJohn Marino benchme = &threadlist[i].bench;
171486d7f5d3SJohn Marino
171586d7f5d3SJohn Marino if (!*benchme || !bit_is_on(selected_benches, i))
171686d7f5d3SJohn Marino continue;
171786d7f5d3SJohn Marino
171886d7f5d3SJohn Marino log_output("--- Benchmarking simulated cpu of %s ", threadlist[i].label);
171986d7f5d3SJohn Marino if (ud.do_rt)
172086d7f5d3SJohn Marino log_output("real time ");
172186d7f5d3SJohn Marino else if (ud.bench_nice)
172286d7f5d3SJohn Marino log_output("nice %d ", ud.bench_nice);
172386d7f5d3SJohn Marino log_output("in the presence of simulated ");
172486d7f5d3SJohn Marino if (ud.load_nice)
172586d7f5d3SJohn Marino log_output("nice %d ", ud.load_nice);
172686d7f5d3SJohn Marino log_output("---\n");
172786d7f5d3SJohn Marino
172886d7f5d3SJohn Marino log_output("Load");
172986d7f5d3SJohn Marino if (ud.do_rt)
173086d7f5d3SJohn Marino log_output("\tLatency +/- SD (us)");
173186d7f5d3SJohn Marino else
173286d7f5d3SJohn Marino log_output("\tLatency +/- SD (ms)");
173386d7f5d3SJohn Marino log_output(" Max Latency ");
173486d7f5d3SJohn Marino log_output(" %% Desired CPU");
173586d7f5d3SJohn Marino if (!thi->nodeadlines)
173686d7f5d3SJohn Marino log_output(" %% Deadlines Met");
173786d7f5d3SJohn Marino log_output("\n");
173886d7f5d3SJohn Marino
173986d7f5d3SJohn Marino for (j = 0 ; j < THREADS ; j++) {
174086d7f5d3SJohn Marino struct thread *thj = &threadlist[j];
174186d7f5d3SJohn Marino
174286d7f5d3SJohn Marino if (j == i || !bit_is_on(selected_loads, j) ||
174386d7f5d3SJohn Marino (!threadlist[j].load && !ud.do_rt) ||
174486d7f5d3SJohn Marino (!threadlist[j].rtload && ud.do_rt))
174586d7f5d3SJohn Marino continue;
174686d7f5d3SJohn Marino log_output("%s\t", thj->label);
174786d7f5d3SJohn Marino sync_flush();
174886d7f5d3SJohn Marino bench(i, j);
174986d7f5d3SJohn Marino }
175086d7f5d3SJohn Marino log_output("\n");
175186d7f5d3SJohn Marino }
175286d7f5d3SJohn Marino log_output("\n");
175386d7f5d3SJohn Marino if (ud.log)
175486d7f5d3SJohn Marino fclose(ud.logfile);
175586d7f5d3SJohn Marino
175686d7f5d3SJohn Marino return 0;
175786d7f5d3SJohn Marino }
1758