void *low_prio_rt_thread(void *arg) { struct thread *t = (struct thread *)arg; while (!thread_quit(t)) { while_not_flag(LOW_START_CYCLE, t) rt_nanosleep(1 * NS_PER_MS); debug(DBG_INFO, "low try mutex\n"); pthread_mutex_lock(&pi_mutex); debug(DBG_INFO, "low grab mutex\n"); write_flag(MED_START_WORK); rt_nanosleep(1 * NS_PER_MS); while_not_flag(LOW_DROP_MUTEX, t) { //printf("!"); fflush(NULL); rt_nanosleep(1); } debug(DBG_INFO, "low drop mutex\n"); low_drop_time = rt_gettime(); pthread_mutex_unlock(&pi_mutex); while_not_flag(END_OF_CYCLE, t) { //printf("@"); fflush(NULL); rt_nanosleep(1 * NS_PER_MS); }
void *periodic_thread(void *thread) { struct thread *t = (struct thread *)thread; struct periodic_arg *parg = (struct periodic_arg *)t->arg; nsec_t period = parg->period; void*(*func)(void*) = parg->func; int i = 0; nsec_t next, now; nsec_t exe_start, exe_end, exe_time; next = rt_gettime(); while (i < parg->iterations) { next += period; if (rt_gettime() > next) { printf("TID %d missed period, aborting\n", t->id); fail[t->id] = 1; break; } exe_start = rt_gettime(); func(parg->arg); exe_end = rt_gettime(); exe_time = exe_end - exe_start; rec.x = i; rec.y = exe_time/NS_PER_US; stats_container_append(&dat[t->id], rec); i++; now = rt_gettime(); if (now > next) { printf("Missed period, aborting (calc took too long)\n"); fail[t->id] = 1; break; } rt_nanosleep(next - now); } printf("TID %d (%c - prio %d) complete\n", t->id, groupname[t->id>>2], t->priority); return NULL; }
int periodic_thread(nsec_t period, int iterations, int loops) { stats_container_t dat; stats_container_t hist; stats_quantiles_t quantiles; stats_record_t rec; int i = 0; int fail = 0; nsec_t next, now; nsec_t exe_start, exe_end, exe_time; char *samples_filename; char *hist_filename; stats_container_init(&dat, iterations); stats_container_init(&hist, HIST_BUCKETS); stats_quantiles_init(&quantiles, (int)log10(iterations)); if (asprintf(&samples_filename, "%s-samples", filename_prefix) == -1) { fprintf(stderr, "Failed to allocate string for samples filename\n"); return -1; } if (asprintf(&hist_filename, "%s-hist", filename_prefix) == -1) { fprintf(stderr, "Failed to allocate string for samples filename\n"); return -1; } next = rt_gettime(); while (i < iterations) { next += period; now = rt_gettime(); if (now > next) { printf("Missed period, aborting (didn't get scheduled in time)\n"); fail = 1; break; } exe_start = rt_gettime(); calc(loops); exe_end = rt_gettime(); exe_time = exe_end - exe_start; rec.x = i; rec.y = exe_time/NS_PER_US; stats_container_append(&dat, rec); i++; now = rt_gettime(); if (now > next) { printf("Missed period, aborting (calc took too long)\n"); fail = 1; break; } rt_nanosleep(next - now); } stats_container_save(samples_filename, "Periodic CPU Load Scatter Plot",\ "Iteration", "Runtime (us)", &dat, "points"); stats_container_save(hist_filename, "Periodic CPU Load Histogram",\ "Runtime (us)", "Samples", &hist, "steps"); printf(" Execution Time Statistics:\n"); printf("Min: %ld us\n", stats_min(&dat)); printf("Max: %ld us\n", stats_max(&dat)); printf("Avg: %.4f us\n", stats_avg(&dat)); printf("StdDev: %.4f us\n", stats_stddev(&dat)); printf("Quantiles:\n"); stats_quantiles_calc(&dat, &quantiles); stats_quantiles_print(&quantiles); printf("Criteria: no missed periods\n"); printf("Result: %s\n", fail ? "FAIL":"PASS"); free(samples_filename); free(hist_filename); return fail; }
void *periodic_thread(void *arg) { int i; nsec_t delay, avg_delay = 0, start_delay, min_delay = -1ULL, max_delay = 0; int failures = 0; nsec_t next = 0, now = 0, sched_delta = 0, delta = 0, prev = 0, iter_start; /* wait for the specified start time */ rt_nanosleep_until(start); now = rt_gettime(); start_delay = (now - start)/NS_PER_US; iter_start = next = now; debug(DBG_INFO, "ITERATION DELAY(US) MAX_DELAY(US) FAILURES\n"); debug(DBG_INFO, "--------- --------- ------------- --------\n"); if (latency_threshold) { latency_trace_enable(); latency_trace_start(); } for (i = 0; i < iterations; i++) { /* wait for the period to start */ next += period; prev = now; now = rt_gettime(); if (next < now) { printf("\nPERIOD MISSED!\n"); printf(" scheduled delta: %8llu us\n", sched_delta/1000); printf(" actual delta: %8llu us\n", delta/1000); printf(" latency: %8llu us\n", (delta-sched_delta)/1000); printf("---------------------------------------\n"); printf(" previous start: %8llu us\n", (prev-iter_start)/1000); printf(" now: %8llu us\n", (now-iter_start)/1000); printf(" scheduled start: %8llu us\n", (next-iter_start)/1000); printf("next scheduled start is in the past!\n"); ret = 1; break; } sched_delta = next - now; /* how long we should sleep */ delta = 0; do { nsec_t new_now; rt_nanosleep(next - now); new_now = rt_gettime(); delta += new_now - now; /* how long we did sleep */ now = new_now; } while (now < next); /* start of period */ delay = (now - iter_start - (nsec_t)(i+1)*period)/NS_PER_US; rec.x = i; rec.y = delay; stats_container_append(&dat, rec); if (delay < min_delay) min_delay = delay; if (delay > max_delay) max_delay = delay; if (delay > pass_criteria) { failures++; ret = 1; } avg_delay += delay; if (latency_threshold && delay > latency_threshold) break; /* continuous status ticker */ debug(DBG_INFO, "%9i %9llu %13llu %8i\r", i, delay, max_delay, failures); fflush(stdout); busy_work_ms(load_ms); } if (latency_threshold) { latency_trace_stop(); if (i != iterations) { printf("Latency threshold (%lluus) exceeded at iteration %d\n", latency_threshold, i); latency_trace_print(); stats_container_resize(&dat, i+1); } } /* save samples before the quantile calculation messes things up! */ stats_hist(&hist, &dat); stats_container_save("samples", "Periodic Scheduling Latency Scatter Plot",\ "Iteration", "Latency (us)", &dat, "points"); stats_container_save("hist", "Periodic Scheduling Latency Histogram",\ "Latency (us)", "Samples", &hist, "steps"); avg_delay /= i; printf("\n\n"); printf("Start: %4llu us: %s\n", start_delay, start_delay < pass_criteria ? "PASS" : "FAIL"); printf("Min: %4llu us: %s\n", min_delay, min_delay < pass_criteria ? "PASS" : "FAIL"); printf("Max: %4llu us: %s\n", max_delay, max_delay < pass_criteria ? "PASS" : "FAIL"); printf("Avg: %4llu us: %s\n", avg_delay, avg_delay < pass_criteria ? "PASS" : "FAIL"); printf("StdDev: %.4f us\n", stats_stddev(&dat)); printf("Quantiles:\n"); stats_quantiles_calc(&dat, &quantiles); stats_quantiles_print(&quantiles); printf("Failed Iterations: %d\n", failures); return NULL; }
int main(int argc, char **argv) { pthread_t *threads; long i; int ret; struct timespec intv; struct sched_param param; rt_init("a:r:t:e:l:h:", parse_args, argc, argv); signal(SIGINT, stop_log); if (argc >= (optind + 1)) nr_tasks = atoi(argv[optind]); else { numcpus = sysconf(_SC_NPROCESSORS_ONLN); nr_tasks = numcpus + 1; } intervals = malloc(sizeof(stats_container_t) * nr_tasks); if (!intervals) debug(DBG_ERR, "malloc failed\n"); memset(intervals, 0, sizeof(stats_container_t) * nr_tasks); intervals_length = malloc(sizeof(stats_container_t) * nr_tasks); if (!intervals_length) debug(DBG_ERR, "malloc failed\n"); memset(intervals_length, 0, sizeof(stats_container_t) * nr_tasks); if (!intervals_loops) debug(DBG_ERR, "malloc failed\n"); intervals_loops = malloc(sizeof(stats_container_t) * nr_tasks); memset(intervals_loops, 0, sizeof(stats_container_t) * nr_tasks); threads = malloc(sizeof(*threads) * nr_tasks); if (!threads) debug(DBG_ERR, "malloc failed\n"); 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) debug(DBG_ERR, "pthread_barrier_init failed: %s\n", strerror(ret)); for (i = 0; i < nr_tasks; i++) { stats_container_init(&intervals[i], nr_runs); stats_container_init(&intervals_length[i], nr_runs); stats_container_init(&intervals_loops[i], nr_runs); } thread_pids = malloc(sizeof(long) * nr_tasks); if (!thread_pids) debug(DBG_ERR, "malloc thread_pids failed\n"); for (i = 0; i < nr_tasks; i++) { threads[i] = create_fifo_thread(start_task, (void *)i, prio_start + i); } /* * 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)) debug(DBG_WARN, "Warning, can't set priority of" "main thread !\n"); intv.tv_sec = INTERVAL / NS_PER_SEC; intv.tv_nsec = INTERVAL % (1 * NS_PER_SEC); print_progress_bar(0); setup_ftrace_marker(); for (loop = 0; loop < nr_runs; loop++) { unsigned long long end; now = rt_gettime() / NS_PER_US; ftrace_write("Loop %d now=%lld\n", loop, now); pthread_barrier_wait(&start_barrier); ftrace_write("All running!!!\n"); rt_nanosleep(intv.tv_nsec); print_progress_bar((loop * 100) / nr_runs); end = rt_gettime() / NS_PER_US; ftrace_write("Loop %d end now=%lld diff=%lld\n", loop, end, end - now); ret = pthread_barrier_wait(&end_barrier); if (stop || (check && check_times(loop))) { loop++; nr_runs = loop; break; } } putc('\n', stderr); pthread_barrier_wait(&start_barrier); done = 1; pthread_barrier_wait(&end_barrier); join_threads(); 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; }