/* * schedcnt by Davide Libenzi ( linux kernel scheduler latency tester ) * Version 0.19 - Copyright (C) 2001 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 scheduler latency using * the "latsched" kernel patch. * Build: * * gcc -o schedcnt schedcnt.c * * Use: * * schedcnt [--samples n] [--sttime u] [--klimit k] [-- cmdpath [arg] ...] * * --samples = Set the size of the sample buffer * --ttime = Set the sample time in seconds * --sttime = Set the sample time in microseconds * --klimit = Set the cut factor for samples. Samples > AVSC*klimit are not evalued in KAVS * -- = Separate the optional command to be executed during the test time * cmdpath = Command to be executed * arg = Command argouments * * The output is, for each cpu : * * CPU NSAMP * SAMP[0] * ... * SAMP[NSAMP-1] * AVSC CHSQ KAVS * * * CPU = CPU number * NSAMP = Number of readed samples * AVSC = Average schedule() cycles * CHSQ = ChiSquare of the CSCH distribution * KAVS = High cut average schedule() cycles * SAMP[i] is in the form : * * CENT CEXT CSCH PPID RTIM * * CENT = Cycle counter at schedule() entry * CEXT = Cycle counter at schedule() exit * CSCH = Cycle duration of schedule() * PPID = New scheduled PID * RTIM = Cycles run time ( this maybe incorrect some time due schedule() nesting ) * */ #include #include #include #include #include #include #include #include #include #include #include #include #define TEST_NUM_SAMPLES 4000 #define SLEEP_SYNC_TIME 1500000 #define STD_SAMPLE_TIME (5 * 1000000) #define STD_KLIMIT 2.0 int main(int argc, char *argv[]) { int ii, res, lsfd, cpu, ncpus, icmd, valid; int samples = TEST_NUM_SAMPLES, sleeptime = STD_SAMPLE_TIME; pid_t expid = -1; unsigned long long schedtime, avgstime; double chisqr, davgstime, klimit = STD_KLIMIT, lmavg; char const * lsfile = "/dev/latsched"; struct lsctl_getdata lsgd; for (ii = 1; ii < argc; ii++) { if (strcmp(argv[ii], "--samples") == 0) { if (++ii < argc) samples = atoi(argv[ii]); continue; } if (strcmp(argv[ii], "--sttime") == 0) { if (++ii < argc) sleeptime = atoi(argv[ii]); continue; } if (strcmp(argv[ii], "--ttime") == 0) { if (++ii < argc) sleeptime = atoi(argv[ii]) * 1000000; continue; } if (strcmp(argv[ii], "--klimit") == 0) { if (++ii < argc) klimit = atof(argv[ii]); continue; } if (strcmp(argv[ii], "--") == 0) { icmd = ++ii; break; } } ncpus = sysconf(_SC_NPROCESSORS_CONF); if ((lsfd = open(lsfile, O_RDWR)) == -1) { perror(lsfile); return 1; } if ((res = ioctl(lsfd, LS_SAMPLES, samples))) { if ((res = ioctl(lsfd, LS_STOP, 0)) || (res = ioctl(lsfd, LS_SAMPLES, samples))) { perror("LS_SAMPLES"); close(lsfd); return 2; } } if ((res = ioctl(lsfd, LS_START, 0))) { perror("LS_START"); close(lsfd); return 3; } if (icmd > 0 && icmd < argc) { expid = fork(); if (expid == -1) { perror("fork"); close(lsfd); return 5; } else if (expid == 0) { setpgid(0, getpid()); execv(argv[icmd], &argv[icmd]); exit(0); } } usleep(sleeptime); if (expid > 0 && kill(-expid, SIGKILL)) perror("SIGKILL"); if ((res = ioctl(lsfd, LS_STOP, 0))) { perror("LS_STOP"); close(lsfd); return 5; } usleep(SLEEP_SYNC_TIME); memset(&lsgd, 0, sizeof(lsgd)); lsgd.size = samples; lsgd.data = (struct latsched_sample *) malloc(samples * sizeof(struct latsched_sample)); for (cpu = 0; cpu < ncpus; cpu++) { lsgd.cpu = cpu; lsgd.size = samples; if ((res = ioctl(lsfd, LS_FETCH, &lsgd))) { perror("LS_FETCH"); close(lsfd); return -1; } fprintf(stdout, "%d\t%d\n", cpu, lsgd.rsize); for (ii = 0, avgstime = 0; ii < lsgd.rsize; ii++) { schedtime = lsgd.data[ii].lss_out - lsgd.data[ii].lss_in; avgstime += schedtime; fprintf(stdout, "%llu\t%llu\t%llu\t%u", lsgd.data[ii].lss_in, lsgd.data[ii].lss_out, schedtime, lsgd.data[ii].lss_pid); if (ii < (lsgd.rsize - 1)) fprintf(stdout, "\t%llu", lsgd.data[ii + 1].lss_in - lsgd.data[ii].lss_in); fprintf(stdout, "\n"); } davgstime = (double) avgstime / (double) lsgd.rsize; for (ii = 0, chisqr = 0.0; ii < lsgd.rsize; ii++) { double difvv = (double) (lsgd.data[ii].lss_out - lsgd.data[ii].lss_in) - (double) davgstime; chisqr += (difvv * difvv) / davgstime; } for (ii = 0, avgstime = 0, valid = 0; ii < lsgd.rsize; ii++) { schedtime = lsgd.data[ii].lss_out - lsgd.data[ii].lss_in; if (schedtime < klimit * davgstime) { avgstime += schedtime; ++valid; } } lmavg = valid > 0 ? (double) avgstime / (double) valid: 0; fprintf(stdout, "%.0lf\t%.0lf\t%.0lf\n", davgstime, chisqr, lmavg); } close(lsfd); return 0; }