/* * lattest by Davide Libenzi ( linux kernel scheduler latency tester ) * Version 0.17 - Copyright (C) 2001, 2003 Davide Libenzi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi * * * The purpose of this tool is to measure the real time tasks latency. * Build: * * gcc -o lattest lattest.c -lrt * * Use: * * lattest [--test-stime s] [--sleep-mstime ms] [--pause-mstime ms] [--priority p] * [--sched-fifo] [--sched-rr] [-- cmdpath [arg] ...] * * --test-stime = Set the test time in seconds * --sleep-mstime = Set the sleep time in milliseconds * --pause-mstime = Set the pause time in milliseconds * --priority = Set the real time task priority ( 0 for OTHER, 1..99 for RT ) * --sched-other = Set the real time task policy to OTHER * --sched-fifo = Set the real time task policy to FIFO * --sched-rr = Set the real time task policy to RR * --sched-softrr = Set the real time task policy to SOFTRR * -- = Separate the optional command to be executed during the test time * cmdpath = Command to be executed * arg = Command argouments * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define STD_SLEEP_TIME 4 #define PAUSE_SLEEP_TIME 200 #define STD_TEST_TIME 8 #if !defined(SCHED_SOFTRR) #define SCHED_SOFTRR 3 #endif #define rdtscll(val) \ __asm__ __volatile__("rdtsc" : "=A" (val)) typedef unsigned long long cycles_t; static volatile int stop_test = 0; static inline cycles_t get_cycles (void) { unsigned long long ret; rdtscll(ret); return ret; } void sig_int(int sig) { ++stop_test; signal(sig, sig_int); } int main(int argc, char *argv[]) { int i, icmd, pausetime = PAUSE_SLEEP_TIME, testtime = STD_TEST_TIME, policy = SCHED_RR, priority = 1, sleeptime = STD_SLEEP_TIME, numsamples; pid_t expid = -1; cycles_t cys, cye, totlat = 0, cylat = 0, mscycles; cycles_t *samples; struct sched_param sp; struct timespec ts1, ts2; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "--test-stime") == 0) { if (++i < argc) testtime = atoi(argv[i]); continue; } if (strcmp(argv[i], "--sleep-mstime") == 0) { if (++i < argc) sleeptime = atoi(argv[i]); continue; } if (strcmp(argv[i], "--pause-mstime") == 0) { if (++i < argc) pausetime = atoi(argv[i]); continue; } if (strcmp(argv[i], "--priority") == 0) { if (++i < argc) priority = atoi(argv[i]); continue; } if (strcmp(argv[i], "--sched-other") == 0) { policy = SCHED_OTHER; priority = 0; continue; } if (strcmp(argv[i], "--sched-fifo") == 0) { policy = SCHED_FIFO; continue; } if (strcmp(argv[i], "--sched-rr") == 0) { policy = SCHED_RR; continue; } if (strcmp(argv[i], "--sched-softrr") == 0) { policy = SCHED_SOFTRR; continue; } if (strcmp(argv[i], "--") == 0) { icmd = ++i; break; } } numsamples = (testtime * 1000) / pausetime + 1; if (!(samples = (cycles_t *) malloc(numsamples * sizeof(cycles_t)))) { perror("malloc"); return 1; } if (icmd > 0 && icmd < argc) { expid = fork(); if (expid == -1) { perror("fork"); return 5; } else if (expid == 0) { setpgid(0, getpid()); execv(argv[icmd], &argv[icmd]); exit(0); } } memset(&sp, 0, sizeof(sp)); sp.sched_priority = priority; if (sched_setscheduler(0, policy, &sp)) { perror("sched_setscheduler"); if (expid > 0 && kill(-expid, SIGKILL)) perror("SIGKILL"); return 4; } signal(SIGINT, sig_int); clock_getres(CLOCK_REALTIME, &ts1); fprintf(stderr, "timeres=%ld\n", ts1.tv_nsec / 1000); clock_gettime(CLOCK_REALTIME, &ts1); cys = get_cycles(); sleep(1); clock_gettime(CLOCK_REALTIME, &ts2); cye = get_cycles(); mscycles = (cye - cys) / ((ts2.tv_sec - ts1.tv_sec) * 1000 + (ts2.tv_nsec - ts1.tv_nsec) / 1000000); fprintf(stderr, "mscycles=%llu\n", mscycles); for (i = 0; i < numsamples && !stop_test; i++) { ts1.tv_sec = 0; ts1.tv_nsec = sleeptime * 1000000; cys = get_cycles(); clock_nanosleep(CLOCK_REALTIME, 0, &ts1, &ts2); cye = get_cycles(); samples[i] = (cye - cys) / mscycles; totlat += samples[i]; if (samples[i] > cylat) cylat = samples[i]; usleep(pausetime * 1000); } numsamples = i; memset(&sp, 0, sizeof(sp)); sp.sched_priority = 0; if (sched_setscheduler(0, SCHED_OTHER, &sp)) { perror("sched_setscheduler"); if (expid > 0 && kill(-expid, SIGKILL)) perror("SIGKILL"); return 6; } if (expid > 0 && kill(-expid, SIGKILL)) perror("SIGKILL"); for (i = 0; i < numsamples; i++) { } fprintf(stdout, "maxlat=%llu\n", cylat); if (numsamples) fprintf(stdout, "avglat=%llu\n", totlat / numsamples); return 0; }