static void burn_nsecs(u64 nsecs) { u64 T0 = get_nsecs(), T1; do { T1 = get_nsecs(); } while (T1 + run_measurement_overhead < T0 + nsecs); }
static void burn_nsecs(struct perf_sched *sched, u64 nsecs) { u64 T0 = get_nsecs(), T1; do { T1 = get_nsecs(); } while (T1 + sched->run_measurement_overhead < T0 + nsecs); }
static void calibrate_run_measurement_overhead(void) { u64 T0, T1, delta, min_delta = 1000000000ULL; int i; for (i = 0; i < 10; i++) { T0 = get_nsecs(); burn_nsecs(0); T1 = get_nsecs(); delta = T1-T0; min_delta = min(min_delta, delta); } run_measurement_overhead = min_delta; printf("run measurement overhead: %Ld nsecs\n", min_delta); }
static void test_calibrations(struct perf_sched *sched) { u64 T0, T1; T0 = get_nsecs(); burn_nsecs(sched, 1e6); T1 = get_nsecs(); printf("the run test took %" PRIu64 " nsecs\n", T1 - T0); T0 = get_nsecs(); sleep_nsecs(1e6); T1 = get_nsecs(); printf("the sleep test took %" PRIu64 " nsecs\n", T1 - T0); }
static void calibrate_run_measurement_overhead(struct perf_sched *sched) { u64 T0, T1, delta, min_delta = 1000000000ULL; int i; for (i = 0; i < 10; i++) { T0 = get_nsecs(); burn_nsecs(sched, 0); T1 = get_nsecs(); delta = T1-T0; min_delta = min(min_delta, delta); } sched->run_measurement_overhead = min_delta; printf("run measurement overhead: %" PRIu64 " nsecs\n", min_delta); }
static void dump_stats(void) { unsigned long now = get_nsecs(); long dt = now - prev_time; int i; prev_time = now; for (i = 0; i < num_socks; i++) { char *fmt = "%-15s %'-11.0f %'-11lu\n"; double rx_pps, tx_pps; rx_pps = (xsks[i]->rx_npkts - xsks[i]->prev_rx_npkts) * 1000000000. / dt; tx_pps = (xsks[i]->tx_npkts - xsks[i]->prev_tx_npkts) * 1000000000. / dt; printf("\n sock%d@", i); print_benchmark(false); printf("\n"); printf("%-15s %-11s %-11s %-11.2f\n", "", "pps", "pkts", dt / 1000000000.); printf(fmt, "rx", rx_pps, xsks[i]->rx_npkts); printf(fmt, "tx", tx_pps, xsks[i]->tx_npkts); xsks[i]->prev_rx_npkts = xsks[i]->rx_npkts; xsks[i]->prev_tx_npkts = xsks[i]->tx_npkts; } }
static void calibrate_sleep_measurement_overhead(void) { u64 T0, T1, delta, min_delta = 1000000000ULL; int i; for (i = 0; i < 10; i++) { T0 = get_nsecs(); sleep_nsecs(10000); T1 = get_nsecs(); delta = T1-T0; min_delta = min(min_delta, delta); } min_delta -= 10000; sleep_measurement_overhead = min_delta; printf("sleep measurement overhead: %Ld nsecs\n", min_delta); }
static void run_one_test(struct perf_sched *sched) { u64 T0, T1, delta, avg_delta, fluct; T0 = get_nsecs(); wait_for_tasks(sched); T1 = get_nsecs(); delta = T1 - T0; sched->sum_runtime += delta; sched->nr_runs++; avg_delta = sched->sum_runtime / sched->nr_runs; if (delta < avg_delta) fluct = avg_delta - delta; else fluct = delta - avg_delta; sched->sum_fluct += fluct; if (!sched->run_avg) sched->run_avg = delta; sched->run_avg = (sched->run_avg * 9 + delta) / 10; printf("#%-3ld: %0.3f, ", sched->nr_runs, (double)delta / 1000000.0); printf("ravg: %0.2f, ", (double)sched->run_avg / 1e6); printf("cpu: %0.2f / %0.2f", (double)sched->cpu_usage / 1e6, (double)sched->runavg_cpu_usage / 1e6); #if 0 /* * rusage statistics done by the parent, these are less * accurate than the sched->sum_exec_runtime based statistics: */ printf(" [%0.2f / %0.2f]", (double)sched->parent_cpu_usage/1e6, (double)sched->runavg_parent_cpu_usage/1e6); #endif printf("\n"); if (sched->nr_sleep_corrections) printf(" (%ld sleep corrections)\n", sched->nr_sleep_corrections); sched->nr_sleep_corrections = 0; }
static gboolean absolute_val_from_string(fvalue_t *fv, char *s, LogFunc logfunc) { struct tm tm; char *curptr; curptr = strptime(s,"%b %d, %Y %H:%M:%S", &tm); if (curptr == NULL) goto fail; tm.tm_isdst = -1; /* let the computer figure out if it's DST */ fv->value.time.secs = mktime(&tm); if (*curptr != '\0') { /* * Something came after the seconds field; it must be * a nanoseconds field. */ if (*curptr != '.') goto fail; /* it's not */ curptr++; /* skip the "." */ if (!isdigit((unsigned char)*curptr)) goto fail; /* not a digit, so not valid */ if (!get_nsecs(curptr, &fv->value.time.nsecs)) goto fail; } else { /* * No nanoseconds value - it's 0. */ fv->value.time.nsecs = 0; } if (fv->value.time.secs == -1) { /* * XXX - should we supply an error message that mentions * that the time specified might be syntactically valid * but might not actually have occurred, e.g. a time in * the non-existent time range after the clocks are * set forward during daylight savings time (or possibly * that it's in the time range after the clocks are set * backward, so that there are two different times that * it could be)? */ goto fail; } return TRUE; fail: if (logfunc != NULL) logfunc("\"%s\" is not a valid absolute time. Example: \"Nov 12, 1999 08:55:44.123\"", s); return FALSE; }
static void wait_for_tasks(struct perf_sched *sched) { u64 cpu_usage_0, cpu_usage_1; struct task_desc *task; unsigned long i, ret; sched->start_time = get_nsecs(); sched->cpu_usage = 0; pthread_mutex_unlock(&sched->work_done_wait_mutex); for (i = 0; i < sched->nr_tasks; i++) { task = sched->tasks[i]; ret = sem_wait(&task->ready_for_work); BUG_ON(ret); sem_init(&task->ready_for_work, 0, 0); } ret = pthread_mutex_lock(&sched->work_done_wait_mutex); BUG_ON(ret); cpu_usage_0 = get_cpu_usage_nsec_parent(); pthread_mutex_unlock(&sched->start_work_mutex); for (i = 0; i < sched->nr_tasks; i++) { task = sched->tasks[i]; ret = sem_wait(&task->work_done_sem); BUG_ON(ret); sem_init(&task->work_done_sem, 0, 0); sched->cpu_usage += task->cpu_usage; task->cpu_usage = 0; } cpu_usage_1 = get_cpu_usage_nsec_parent(); if (!sched->runavg_cpu_usage) sched->runavg_cpu_usage = sched->cpu_usage; sched->runavg_cpu_usage = (sched->runavg_cpu_usage * 9 + sched->cpu_usage) / 10; sched->parent_cpu_usage = cpu_usage_1 - cpu_usage_0; if (!sched->runavg_parent_cpu_usage) sched->runavg_parent_cpu_usage = sched->parent_cpu_usage; sched->runavg_parent_cpu_usage = (sched->runavg_parent_cpu_usage * 9 + sched->parent_cpu_usage)/10; ret = pthread_mutex_lock(&sched->start_work_mutex); BUG_ON(ret); for (i = 0; i < sched->nr_tasks; i++) { task = sched->tasks[i]; sem_init(&task->sleep_sem, 0, 0); task->curr_event = 0; } }
static gboolean relative_val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg) { const char *curptr; char *endptr; gboolean negative = FALSE; curptr = s; if(*curptr == '-') { negative = TRUE; curptr++; } /* * If it doesn't begin with ".", it should contain a seconds * value. */ if (*curptr != '.') { /* * Get the seconds value. */ fv->value.time.secs = strtoul(curptr, &endptr, 10); if (endptr == curptr || (*endptr != '\0' && *endptr != '.')) goto fail; curptr = endptr; if (*curptr == '.') curptr++; /* skip the decimal point */ } else { /* * No seconds value - it's 0. */ fv->value.time.secs = 0; curptr++; /* skip the decimal point */ } /* * If there's more stuff left in the string, it should be the * nanoseconds value. */ if (*curptr != '\0') { /* * Get the nanoseconds value. */ if (!get_nsecs(curptr, &fv->value.time.nsecs)) goto fail; } else { /* * No nanoseconds value - it's 0. */ fv->value.time.nsecs = 0; } if(negative) { fv->value.time.secs = -fv->value.time.secs; fv->value.time.nsecs = -fv->value.time.nsecs; } return TRUE; fail: if (err_msg != NULL) *err_msg = g_strdup_printf("\"%s\" is not a valid time.", s); return FALSE; }
j = i + 1; if (j == nr_tasks) j = 0; task2 = tasks[j]; add_sched_event_wakeup(task1, 0, task2); } } static void process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom) { int ret = 0; u64 now; long long delta; now = get_nsecs(); delta = start_time + atom->timestamp - now; switch (atom->type) { case SCHED_EVENT_RUN: burn_nsecs(atom->duration); break; case SCHED_EVENT_SLEEP: if (atom->wait_sem) ret = sem_wait(atom->wait_sem); BUG_ON(ret); break; case SCHED_EVENT_WAKEUP: if (atom->wait_sem) ret = sem_post(atom->wait_sem); BUG_ON(ret);
int main(int argc, char **argv) { struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; struct bpf_prog_load_attr prog_load_attr = { .prog_type = BPF_PROG_TYPE_XDP, }; int prog_fd, qidconf_map, xsks_map; struct bpf_object *obj; char xdp_filename[256]; struct bpf_map *map; int i, ret, key = 0; pthread_t pt; parse_command_line(argc, argv); if (setrlimit(RLIMIT_MEMLOCK, &r)) { fprintf(stderr, "ERROR: setrlimit(RLIMIT_MEMLOCK) \"%s\"\n", strerror(errno)); exit(EXIT_FAILURE); } snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.o", argv[0]); prog_load_attr.file = xdp_filename; if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) exit(EXIT_FAILURE); if (prog_fd < 0) { fprintf(stderr, "ERROR: no program found: %s\n", strerror(prog_fd)); exit(EXIT_FAILURE); } map = bpf_object__find_map_by_name(obj, "qidconf_map"); qidconf_map = bpf_map__fd(map); if (qidconf_map < 0) { fprintf(stderr, "ERROR: no qidconf map found: %s\n", strerror(qidconf_map)); exit(EXIT_FAILURE); } map = bpf_object__find_map_by_name(obj, "xsks_map"); xsks_map = bpf_map__fd(map); if (xsks_map < 0) { fprintf(stderr, "ERROR: no xsks map found: %s\n", strerror(xsks_map)); exit(EXIT_FAILURE); } if (bpf_set_link_xdp_fd(opt_ifindex, prog_fd, opt_xdp_flags) < 0) { fprintf(stderr, "ERROR: link set xdp fd failed\n"); exit(EXIT_FAILURE); } ret = bpf_map_update_elem(qidconf_map, &key, &opt_queue, 0); if (ret) { fprintf(stderr, "ERROR: bpf_map_update_elem qidconf\n"); exit(EXIT_FAILURE); } /* Create sockets... */ xsks[num_socks++] = xsk_configure(NULL); #if RR_LB for (i = 0; i < MAX_SOCKS - 1; i++) xsks[num_socks++] = xsk_configure(xsks[0]->umem); #endif /* ...and insert them into the map. */ for (i = 0; i < num_socks; i++) { key = i; ret = bpf_map_update_elem(xsks_map, &key, &xsks[i]->sfd, 0); if (ret) { fprintf(stderr, "ERROR: bpf_map_update_elem %d\n", i); exit(EXIT_FAILURE); } } signal(SIGINT, int_exit); signal(SIGTERM, int_exit); signal(SIGABRT, int_exit); setlocale(LC_ALL, ""); ret = pthread_create(&pt, NULL, poller, NULL); lassert(ret == 0); prev_time = get_nsecs(); if (opt_bench == BENCH_RXDROP) rx_drop_all(); else if (opt_bench == BENCH_TXONLY) tx_only(xsks[0]); else l2fwd(xsks[0]); return 0; }