From: Subrata Modak <subrata@linux.vnet.ibm.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: ltp-list <ltp-list@lists.sf.net>,
linux-rt-users <linux-rt-users@vger.kernel.org>,
dvhltc <dvhltc@linux.vnet.ibm.com>,
Gregory Haskins <ghaskins@novell.com>,
Clark Williams <clark.williams@gmail.com>
Subject: Re: [LTP] LTP RT Tests (Cyclic, rt-migrate, etc)
Date: Mon, 06 Jul 2009 20:01:38 +0530 [thread overview]
Message-ID: <1246890698.4887.24.camel@subratamodak.linux.ibm.com> (raw)
In-Reply-To: <alpine.DEB.2.00.0907061024200.8813@gandalf.stny.rr.com>
[-- Attachment #1: Type: text/plain, Size: 1409 bytes --]
On Mon, 2009-07-06 at 10:26 -0400, Steven Rostedt wrote:
>
> On Tue, 23 Jun 2009, Subrata Modak wrote:
>
> > Steven,
> >
> > Do you remember this ?
>
> Yes, and I finally got time to fix it up a little ;-)
Great. Forwarding to the ltp mailing list as well. Thanks steven.
Regards--
Subrata
>
> OK, here it is. To run it, just do:
>
> ./rt-migrate-test -c
>
> You need to be root since it changes the priorities. It will check the
> number of processors and create N+1 threads (where N is the number of
> processors). Each thread will wake up at the same time and try to do a
> busy loop for 20 millisecs. If a lower prio thread runs for 1ms before a
> higher prio thread, it will fail. This should test the migration of the
> threads to make sure that the higher prio threads run first.
>
> Sorry for taking so long.
>
> -- Steve
>
>
>
> >
> > Regards--
> > Subrata
> >
> > On Mon, 2008-12-15 at 08:52 -0500, Steven Rostedt wrote:
> > > On Mon, 15 Dec 2008, Subrata Modak wrote:
> > > > >
> > > > > Lets see, you wanted my rt migration test. I'll clean that up now. Is
> > > >
> > > > Oh yes.
> > >
> > > OK, I'm cleaning it up to be more for production use.
> > >
> > > >
> > > > > there something else I needed to send you? If you remember.
> > > >
> > > > I am not quite sure now. Will let you know in future.
> > >
> > > OK, thanks,
> > >
> > > -- Steve
> > >
> >
> >
[-- Attachment #2: rt-migrate-test.c --]
[-- Type: text/x-csrc, Size: 13409 bytes --]
/*
* rt-migrate-test.c
*
* Copyright (C) 2007-2009 Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 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; version 2 of the License (not later!)
*
* 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
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define _GNU_SOURCE
#include <stdio.h>
#ifndef __USE_XOPEN2K
# define __USE_XOPEN2K
#endif
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <stdarg.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include <linux/unistd.h>
#include <sys/syscall.h>
#include <errno.h>
#include <sched.h>
#include <pthread.h>
#ifdef LOGDEV
# include <dump_log.h>
# define do_logdev_open() open("/debug/logdev/write", O_WRONLY)
# define do_logdev_close(ld) close(ld)
__thread char buff[BUFSIZ];
static lgprint(int fd, const char *fmt, ...)
{
va_list ap;
int n;
va_start(ap, fmt);
n = vsnprintf(buff, BUFSIZ, fmt, ap);
va_end(ap);
write(fd, buff, n);
}
#else
# define do_logdev_open() (0)
# define do_logdev_close(lfd) do { } while(0)
# define logdev_print_set(x) do { } while(0)
# define logdev_switch_set(x) do { } while(0)
# define lgprint(x...) do { } while(0)
#endif
#define gettid() syscall(__NR_gettid)
#define VERSION_STRING "V 0.3"
int nr_tasks;
int lfd;
#define nano2sec(nan) (nan / 1000000000ULL)
#define nano2ms(nan) (nan / 1000000ULL)
#define nano2usec(nan) (nan / 1000ULL)
#define usec2nano(sec) (sec * 1000ULL)
#define ms2nano(ms) (ms * 1000000ULL)
#define sec2nano(sec) (sec * 1000000000ULL)
#define INTERVAL ms2nano(100ULL)
#define RUN_INTERVAL ms2nano(20ULL)
#define NR_RUNS 50
#define PRIO_START 2
/* 1 millisec off */
#define MAX_ERR usec2nano(1000)
#define PROGRESS_CHARS 70
static unsigned long long interval = INTERVAL;
static unsigned long long run_interval = RUN_INTERVAL;
static unsigned long long max_err = MAX_ERR;
static int nr_runs = NR_RUNS;
static int prio_start = PRIO_START;
static int check;
static int stop;
static unsigned long long now;
static int done;
static int loop;
static pthread_barrier_t start_barrier;
static pthread_barrier_t end_barrier;
static unsigned long long **intervals;
static unsigned long long **intervals_length;
static unsigned long **intervals_loops;
static long *thread_pids;
static char buffer[BUFSIZ];
static void perr(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsnprintf(buffer, BUFSIZ, fmt, ap);
va_end(ap);
perror(buffer);
fflush(stderr);
exit(-1);
}
static void print_progress_bar(int percent)
{
int i;
int p;
if (percent > 100)
percent = 100;
/* Use stderr, so we don't capture it */
putc('\r', stderr);
putc('|', stderr);
for (i=0; i < PROGRESS_CHARS; i++)
putc(' ', stderr);
putc('|', stderr);
putc('\r', stderr);
putc('|', stderr);
p = PROGRESS_CHARS * percent / 100;
for (i=0; i < p; i++)
putc('-', stderr);
fflush(stderr);
}
static void usage(char **argv)
{
char *arg = argv[0];
char *p = arg+strlen(arg);
while (p >= arg && *p != '/')
p--;
p++;
printf("%s %s\n", p, VERSION_STRING);
printf("Usage:\n"
"%s <options> nr_tasks\n\n"
"-p prio --prio prio base priority to start RT tasks with (2) \n"
"-r time --run-time time Run time (ms) to busy loop the threads (20)\n"
"-s time --sleep-time time Sleep time (ms) between intervals (100)\n"
"-m time --maxerr time Max allowed error (microsecs)\n"
"-l loops --loops loops Number of iterations to run (50)\n"
"-c --check Stop if lower prio task is quick than higher (off)\n"
" () above are defaults \n",
p);
exit(0);
}
static void parse_options (int argc, char *argv[])
{
for (;;) {
int option_index = 0;
/** Options for getopt */
static struct option long_options[] = {
{"prio", required_argument, NULL, 'p'},
{"run-time", required_argument, NULL, 'r'},
{"sleep-time", required_argument, NULL, 's'},
{"maxerr", required_argument, NULL, 'm'},
{"loops", required_argument, NULL, 'l'},
{"check", no_argument, NULL, 'c'},
{"help", no_argument, NULL, '?'},
{NULL, 0, NULL, 0}
};
int c = getopt_long (argc, argv, "p:r:s:m:l:ch",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'p': prio_start = atoi(optarg); break;
case 'r':
run_interval = atoi(optarg);
break;
case 's': interval = atoi(optarg); break;
case 'l': nr_runs = atoi(optarg); break;
case 'm': max_err = usec2nano(atoi(optarg)); break;
case 'c': check = 1; break;
case '?':
case 'h':
usage(argv);
break;
}
}
}
static unsigned long long get_time(void)
{
struct timeval tv;
unsigned long long time;
gettimeofday(&tv, NULL);
time = sec2nano(tv.tv_sec);
time += usec2nano(tv.tv_usec);
return time;
}
static void record_time(int id, unsigned long long time, unsigned long l)
{
unsigned long long ltime;
if (loop >= nr_runs)
return;
time -= now;
ltime = get_time();
ltime -= now;
intervals[loop][id] = time;
intervals_length[loop][id] = ltime;
intervals_loops[loop][id] = l;
}
static void print_results(void)
{
int i;
int t;
unsigned long long tasks_max[nr_tasks];
unsigned long long tasks_min[nr_tasks];
unsigned long long tasks_avg[nr_tasks];
memset(tasks_max, 0, sizeof(tasks_max[0])*nr_tasks);
memset(tasks_min, 0xff, sizeof(tasks_min[0])*nr_tasks);
memset(tasks_avg, 0, sizeof(tasks_avg[0])*nr_tasks);
printf("Iter: ");
for (t=0; t < nr_tasks; t++)
printf("%6d ", t);
printf("\n");
for (i=0; i < nr_runs; i++) {
printf("%4d: ", i);
for (t=0; t < nr_tasks; t++) {
unsigned long long itv = intervals[i][t];
if (tasks_max[t] < itv)
tasks_max[t] = itv;
if (tasks_min[t] > itv)
tasks_min[t] = itv;
tasks_avg[t] += itv;
printf("%6lld ", nano2usec(itv));
}
printf("\n");
printf(" len: ");
for (t=0; t < nr_tasks; t++) {
unsigned long long len = intervals_length[i][t];
printf("%6lld ", nano2usec(len));
}
printf("\n");
printf(" loops: ");
for (t=0; t < nr_tasks; t++) {
unsigned long loops = intervals_loops[i][t];
printf("%6ld ", loops);
}
printf("\n");
printf("\n");
}
printf("Parent pid: %d\n", getpid());
for (t=0; t < nr_tasks; t++) {
printf(" Task %d (prio %d) (pid %ld):\n", t, t + prio_start,
thread_pids[t]);
printf(" Max: %lld us\n", nano2usec(tasks_max[t]));
printf(" Min: %lld us\n", nano2usec(tasks_min[t]));
printf(" Tot: %lld us\n", nano2usec(tasks_avg[t]));
printf(" Avg: %lld us\n", nano2usec(tasks_avg[t] / nr_runs));
printf("\n");
}
if (check) {
if (check < 0)
printf(" Failed!\n");
else
printf(" Passed!\n");
}
}
static unsigned long busy_loop(unsigned long long start_time)
{
unsigned long long time;
unsigned long l = 0;
do {
l++;
time = get_time();
} while ((time - start_time) < RUN_INTERVAL);
return l;
}
void *start_task(void *data)
{
long id = (long)data;
unsigned long long start_time;
struct sched_param param = {
.sched_priority = id + prio_start,
};
int ret;
int high = 0;
cpu_set_t cpumask;
cpu_set_t save_cpumask;
int cpu = 0;
unsigned long l;
long pid;
ret = sched_getaffinity(0, sizeof(save_cpumask), &save_cpumask);
if (ret < 0)
perr("getting affinity");
pid = gettid();
/* Check if we are the highest prio task */
if (id == nr_tasks-1)
high = 1;
ret = sched_setscheduler(0, SCHED_FIFO, ¶m);
if (ret < 0 && !id)
fprintf(stderr, "Warning, can't set priorities\n");
while (!done) {
if (high) {
/* rotate around the CPUS */
if (!CPU_ISSET(cpu, &save_cpumask))
cpu = 0;
CPU_ZERO(&cpumask);
CPU_SET(cpu, &cpumask); cpu++;
sched_setaffinity(0, sizeof(cpumask), &cpumask);
}
pthread_barrier_wait(&start_barrier);
start_time = get_time();
lgprint(lfd, "Thread %d: started %lld diff %lld\n",
pid, start_time, start_time - now);
l = busy_loop(start_time);
record_time(id, start_time, l);
pthread_barrier_wait(&end_barrier);
}
return (void*)pid;
}
static int check_times(int l)
{
int i;
unsigned long long last;
unsigned long long last_loops;
unsigned long long last_length;
for (i=0; i < nr_tasks; i++) {
if (i && last < intervals[l][i] &&
((intervals[l][i] - last) > max_err)) {
/*
* May be a false positive.
* Make sure that we did more loops
* our start is before the end
* and the end should be tested.
*/
if (intervals_loops[l][i] < last_loops ||
intervals[l][i] > last_length ||
(intervals_length[l][i] > last_length &&
intervals_length[l][i] - last_length > max_err)) {
check = -1;
return 1;
}
}
last = intervals[l][i];
last_loops = intervals_loops[l][i];
last_length = intervals_length[l][i];
}
return 0;
}
static void stop_log(int sig)
{
logdev_print_set(0);
logdev_switch_set(0);
stop = 1;
}
static int count_cpus(void)
{
FILE *fp;
char buf[1024];
int cpus = 0;
char *pbuf;
size_t *pn;
size_t n;
int r;
n = 1024;
pn = &n;
pbuf = buf;
fp = fopen("/proc/cpuinfo", "r");
if (!fp)
perr("Can not read cpuinfo");
while ((r = getline(&pbuf, pn, fp)) >= 0) {
char *p;
if (strncmp(buf, "processor", 9) != 0)
continue;
for (p = buf+9; isspace(*p); p++)
;
if (*p == ':')
cpus++;
}
fclose(fp);
return cpus;
}
int main (int argc, char **argv)
{
pthread_t *threads;
long i;
int ret;
struct timespec intv;
struct sched_param param;
parse_options(argc, argv);
signal(SIGINT, stop_log);
if (argc >= (optind + 1))
nr_tasks = atoi(argv[optind]);
else
nr_tasks = count_cpus() + 1;
threads = malloc(sizeof(*threads) * nr_tasks);
if (!threads)
perr("malloc");
memset(threads, 0, sizeof(*threads) * nr_tasks);
ret = pthread_barrier_init(&start_barrier, NULL, nr_tasks + 1);
ret = pthread_barrier_init(&end_barrier, NULL, nr_tasks + 1);
if (ret < 0)
perr("pthread_barrier_init");
intervals = malloc(sizeof(void*) * nr_runs);
if (!intervals)
perr("malloc intervals array");
intervals_length = malloc(sizeof(void*) * nr_runs);
if (!intervals_length)
perr("malloc intervals length array");
intervals_loops = malloc(sizeof(void*) * nr_runs);
if (!intervals_loops)
perr("malloc intervals loops array");
thread_pids = malloc(sizeof(long) * nr_tasks);
if (!thread_pids)
perr("malloc thread_pids");
for (i=0; i < nr_runs; i++) {
intervals[i] = malloc(sizeof(unsigned long long)*nr_tasks);
if (!intervals[i])
perr("malloc intervals");
memset(intervals[i], 0, sizeof(unsigned long long)*nr_tasks);
intervals_length[i] = malloc(sizeof(unsigned long long)*nr_tasks);
if (!intervals_length[i])
perr("malloc length intervals");
memset(intervals_length[i], 0, sizeof(unsigned long long)*nr_tasks);
intervals_loops[i] = malloc(sizeof(unsigned long)*nr_tasks);
if (!intervals_loops[i])
perr("malloc loops intervals");
memset(intervals_loops[i], 0, sizeof(unsigned long)*nr_tasks);
}
for (i=0; i < nr_tasks; i++) {
if (pthread_create(&threads[i], NULL, start_task, (void *)i))
perr("pthread_create");
}
/*
* Progress bar uses stderr to let users see it when
* redirecting output. So we convert stderr to use line
* buffering so the progress bar doesn't flicker.
*/
setlinebuf(stderr);
/* up our prio above all tasks */
memset(¶m, 0, sizeof(param));
param.sched_priority = nr_tasks + prio_start;
if (sched_setscheduler(0, SCHED_FIFO, ¶m))
fprintf(stderr, "Warning, can't set priority of main thread!\n");
intv.tv_sec = nano2sec(INTERVAL);
intv.tv_nsec = INTERVAL % sec2nano(1);
print_progress_bar(0);
lfd = do_logdev_open();
logdev_print_set(1);
logdev_switch_set(1);
for (loop=0; loop < nr_runs; loop++) {
unsigned long long end;
now = get_time();
lgprint(lfd, "Loop %d now=%lld\n", loop, now);
pthread_barrier_wait(&start_barrier);
lgprint(lfd, "All running!!!\n");
nanosleep(&intv, NULL);
print_progress_bar((loop * 100)/ nr_runs);
end = get_time();
lgprint(lfd, "Loop %d end now=%lld diff=%lld\n", loop, end, end - now);
pthread_barrier_wait(&end_barrier);
if (stop || (check && check_times(loop))) {
loop++;
nr_runs = loop;
break;
}
}
do_logdev_close(lfd);
putc('\n', stderr);
pthread_barrier_wait(&start_barrier);
done = 1;
pthread_barrier_wait(&end_barrier);
for (i=0; i < nr_tasks; i++)
pthread_join(threads[i], (void*)&thread_pids[i]);
logdev_print_set(0);
logdev_switch_set(0);
print_results();
if (stop) {
/*
* We use this test in bash while loops
* So if we hit Ctrl-C then let the while
* loop know to break.
*/
if (check < 0)
exit(-1);
else
exit(1);
}
if (check < 0)
exit(-1);
else
exit(0);
return 0;
}
[-- Attachment #3: Type: text/plain, Size: 79 bytes --]
------------------------------------------------------------------------------
[-- Attachment #4: Type: text/plain, Size: 155 bytes --]
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
next parent reply other threads:[~2009-07-06 14:32 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1224509719.5152.116.camel@subratamodak.linux.ibm.com>
[not found] ` <1224840077.5270.69.camel@subratamodak.linux.ibm.com>
[not found] ` <alpine.DEB.1.10.0810240749470.25677@gandalf.stny.rr.com>
[not found] ` <1229093480.5171.60.camel@subratamodak.linux.ibm.com>
[not found] ` <alpine.DEB.1.10.0812121533350.29763@gandalf.stny.rr.com>
[not found] ` <1229347938.5353.8.camel@subratamodak.linux.ibm.com>
[not found] ` <alpine.DEB.1.10.0812150851290.18692@gandalf.stny.rr.com>
[not found] ` <1245768486.4860.53.camel@subratamodak.linux.ibm.com>
[not found] ` <alpine.DEB.2.00.0907061024200.8813@gandalf.stny.rr.com>
2009-07-06 14:31 ` Subrata Modak [this message]
2009-07-08 18:13 ` [LTP] LTP RT Tests (Cyclic, rt-migrate, etc) Subrata Modak
2009-07-10 16:30 ` Sripathi Kodi
2009-07-10 16:47 ` Subrata Modak
2009-07-10 18:28 ` Darren Hart
2009-07-20 14:43 ` Steven Rostedt
2009-07-20 14:52 ` Gregory Haskins
2009-07-20 17:03 ` Darren Hart
2009-07-30 18:28 ` Subrata Modak
2009-07-30 18:42 ` Steven Rostedt
2009-07-30 19:49 ` Darren Hart
2009-07-30 20:03 ` Steven Rostedt
2009-07-30 20:10 ` Darren Hart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1246890698.4887.24.camel@subratamodak.linux.ibm.com \
--to=subrata@linux.vnet.ibm.com \
--cc=clark.williams@gmail.com \
--cc=dvhltc@linux.vnet.ibm.com \
--cc=ghaskins@novell.com \
--cc=linux-rt-users@vger.kernel.org \
--cc=ltp-list@lists.sf.net \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox