void *func_noise(void *arg) { struct thread *pthr = (struct thread *)arg; int i, tid = gettid(); printf("Noise Thread %d started running with prio %d\n", tid,\ pthr->priority); pthread_barrier_wait(&barrier); /* Let others wait at conditional variable */ usleep(1000); /* Noise thread begins the test */ pthread_mutex_lock(&cond_mutex); pthread_cond_broadcast(&cond_var); pthread_mutex_unlock(&cond_mutex); for (i = 0; i < 10000; i++) { if (i%100 == 0) { printf("Noise Thread %d loop %d pthread pol %d "\ "pri %d\n", tid, i, pthr->policy,\ pthr->priority); fflush(NULL); } busy_work_ms(1); } return NULL; }
void *func_lowrt(void *arg) { struct thread *pthr = (struct thread *)arg; int i, tid = gettid(); printf("Thread %d started running with priority %d\n", tid,\ pthr->priority); pthread_mutex_lock(&glob_mutex); printf("Thread %d at start pthread pol %d pri %d - Got global lock\n",\ tid, pthr->policy, pthr->priority); /* Wait for other RT threads to start up */ pthread_barrier_wait(&barrier); /* Wait for the high priority noise thread to start and signal us */ pthread_mutex_lock(&cond_mutex); pthread_cond_wait(&cond_var, &cond_mutex); pthread_mutex_unlock(&cond_mutex); for (i = 0; i < 10000; i++) { if (i%100 == 0) { printf("Thread %d loop %d pthread pol %d pri %d\n",\ tid, i, pthr->policy, pthr->priority); fflush(NULL); } busy_work_ms(1); } pthread_mutex_unlock(&glob_mutex); return NULL; }
void *func_rt(void *arg) { struct thread *pthr = (struct thread *)arg; int i, tid = gettid(); printf("Thread %d started running with prio %d\n", tid, pthr->priority); pthread_barrier_wait(&barrier); pthread_mutex_lock(&glob_mutex); printf("Thread %d at start pthread pol %d pri %d - Got global lock\n",\ tid, pthr->policy, pthr->priority); /* We just use the mutex as something to slow things down, * say who we are and then do nothing for a while. The aim * of this is to show that high priority threads make more * progress than lower priority threads.. */ for (i = 0; i < 1000; i++) { if (i%100 == 0) { printf("Thread %d loop %d pthread pol %d pri %d\n",\ tid, i, pthr->policy, pthr->priority); fflush(NULL); } busy_work_ms(1); } pthread_mutex_unlock(&glob_mutex); return NULL; }
void * high_prio_thread(void *arg) { nsec_t high_start, high_end, high_get_lock; unsigned int i; stats_container_init(&cpu_delay_dat, iterations); stats_container_init(&cpu_delay_hist, HIST_BUCKETS); stats_quantiles_init(&cpu_delay_quantiles, (int)log10(iterations)); printf("High prio thread started\n"); for (i = 0; i < iterations; i++) { /* Wait for all threads to reach barrier wait. When woken up, low prio thread will own the mutex */ pthread_barrier_wait(&bar1); high_start = rt_gettime(); pthread_mutex_lock(&lock); high_end = rt_gettime(); high_get_lock = high_end - low_unlock; busy_work_ms(high_work_time); pthread_mutex_unlock(&lock); rec.x = i; rec.y = high_get_lock / NS_PER_US; stats_container_append(&cpu_delay_dat, rec); /* Wait for all threads to finish this iteration */ pthread_barrier_wait(&bar2); } stats_hist(&cpu_delay_hist, &cpu_delay_dat); stats_container_save("samples", "pi_perf Latency Scatter Plot", "Iteration", "Latency (us)", &cpu_delay_dat, "points"); stats_container_save("hist", "pi_perf Latency Histogram", "Latency (us)", "Samples", &cpu_delay_hist, "steps"); printf("Time taken for high prio thread to get the lock once released by low prio thread\n"); printf("Min delay = %ld us\n", stats_min(&cpu_delay_dat)); printf("Max delay = %ld us\n", stats_max(&cpu_delay_dat)); printf("Average delay = %4.2f us\n", stats_avg(&cpu_delay_dat)); printf("Standard Deviation = %4.2f us\n", stats_stddev(&cpu_delay_dat)); printf("Quantiles:\n"); stats_quantiles_calc(&cpu_delay_dat, &cpu_delay_quantiles); stats_quantiles_print(&cpu_delay_quantiles); max_pi_delay = stats_max(&cpu_delay_dat); return NULL; }
void * busy_thread(void *arg) { struct thread *thr = (struct thread *)arg; printf("Busy %ld started\n", (long)thr->arg); while (!end) { /* Wait for all threads to reach barrier wait */ pthread_barrier_wait(&bar1); busy_work_ms(busy_work_time); /* Wait for all threads to finish this iteration */ pthread_barrier_wait(&bar2); } return NULL; }
void * low_prio_thread(void *arg) { nsec_t low_start, low_hold; unsigned int i; stats_container_init(&low_dat, iterations); printf("Low prio thread started\n"); for (i = 0; i < iterations; i++) { pthread_mutex_lock(&lock); /* Wait for all threads to reach barrier wait. Since we already own the mutex, high prio thread will boost our priority. */ pthread_barrier_wait(&bar1); low_start = rt_gettime(); busy_work_ms(low_work_time); low_unlock = rt_gettime(); low_hold = low_unlock - low_start; pthread_mutex_unlock(&lock); rec.x = i; rec.y = low_hold / NS_PER_US; stats_container_append(&low_dat, rec); if (i == iterations-1) end = 1; /* Wait for all threads to finish this iteration */ pthread_barrier_wait(&bar2); } return NULL; }
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; }