int main(int argc, char **argv) { sigset_t mask, oldmask; union sched_config *p; size_t len; int ret; mlockall(MCL_CURRENT | MCL_FUTURE); /* * For a recurring global time frame of 400 ms, we define a TP * schedule as follows: * * - thread(s) assigned to partition #2 (tag C) shall be * allowed to run for 100 ms, when the next global time frame * begins. * * - thread(s) assigned to partition #1 (tag B) shall be * allowed to run for 50 ms, after the previous time slot * ends. * * - thread(s) assigned to partition #0 (tag A) shall be * allowed to run for 20 ms, after the previous time slot * ends. * * - when the previous time slot ends, no TP thread shall be * allowed to run until the global time frame ends (special * setting of ptid == -1), i.e. 230 ms. */ len = sched_tp_confsz(NR_WINDOWS); p = malloc(len); if (p == NULL) error(1, ENOMEM, "malloc"); p->tp.nr_windows = NR_WINDOWS; p->tp.windows[0].offset.tv_sec = 0; p->tp.windows[0].offset.tv_nsec = 0; p->tp.windows[0].duration.tv_sec = 0; p->tp.windows[0].duration.tv_nsec = 100000000; p->tp.windows[0].ptid = 2; p->tp.windows[1].offset.tv_sec = 0; p->tp.windows[1].offset.tv_nsec = 100000000; p->tp.windows[1].duration.tv_sec = 0; p->tp.windows[1].duration.tv_nsec = 50000000; p->tp.windows[1].ptid = 1; p->tp.windows[2].offset.tv_sec = 0; p->tp.windows[2].offset.tv_nsec = 150000000; p->tp.windows[2].duration.tv_sec = 0; p->tp.windows[2].duration.tv_nsec = 20000000; p->tp.windows[2].ptid = 0; p->tp.windows[3].offset.tv_sec = 0; p->tp.windows[3].offset.tv_nsec = 170000000; p->tp.windows[3].duration.tv_sec = 0; p->tp.windows[3].duration.tv_nsec = 230000000; p->tp.windows[3].ptid = -1; /* Assign the TP schedule to CPU #0 */ ret = sched_setconfig_np(0, SCHED_TP, p, len); if (ret) error(1, ret, "sched_setconfig_np"); sigemptyset(&mask); sigaddset(&mask, SIGINT); signal(SIGINT, cleanup); sigaddset(&mask, SIGTERM); signal(SIGTERM, cleanup); sigaddset(&mask, SIGHUP); signal(SIGHUP, cleanup); pthread_sigmask(SIG_BLOCK, &mask, &oldmask); sem_init(&barrier, 0, 0); create_thread(threadA, 0); create_thread(threadB, 1); create_thread(threadC, 2); sem_post(&barrier); sigsuspend(&oldmask); return 0; }
static double run_quota(int quota) { size_t len = sched_quota_confsz(); unsigned long long count; union sched_config cf; struct timespec req; int ret, tgid, n; double percent; char label[8]; cf.quota.op = sched_quota_add; cf.quota.add.pshared = 0; ret = sched_setconfig_np(0, SCHED_QUOTA, &cf, len); if (ret) error(1, ret, "sched_setconfig_np(add-quota-group)"); tgid = cf.quota.info.tgid; cf.quota.op = sched_quota_set; cf.quota.set.quota = quota; cf.quota.set.quota_peak = quota; cf.quota.set.tgid = tgid; ret = sched_setconfig_np(0, SCHED_QUOTA, &cf, len); if (ret) error(1, ret, "sched_setconfig_np(set-quota, tgid=%d)", tgid); printf("new thread group #%d on CPU0, quota sum is %d%%\n", tgid, cf.quota.info.quota_sum); for (n = 0; n < nrthreads; n++) { sprintf(label, "t%d", n); create_quota_thread(threads[n], label, tgid, counts[n]); sem_wait(&ready); } pthread_mutex_lock(&lock); started = 1; pthread_cond_broadcast(&barrier); pthread_mutex_unlock(&lock); req.tv_sec = TEST_SECS; req.tv_nsec = 0; clock_nanosleep(CLOCK_MONOTONIC, 0, &req, NULL); for (n = 0, count = 0; n < nrthreads; n++) { count += counts[n]; pthread_kill(threads[n], SIGDEMT); } percent = ((double)count / TEST_SECS) * 100.0 / loops_per_sec; for (n = 0; n < nrthreads; n++) { __real_printf("done quota_thread[%d], count=%lu\n", n, counts[n]); pthread_cancel(threads[n]); pthread_join(threads[n], NULL); } cf.quota.op = sched_quota_remove; cf.quota.remove.tgid = tgid; ret = sched_setconfig_np(0, SCHED_QUOTA, &cf, len); if (ret) error(1, ret, "sched_setconfig_np(remove-quota-group)"); return percent; }