/** * \brief computes the differences of two time stamps with respecting overflow * * This function also accounts for the overhead when taking timestamps * * \param tsc_start timestamp of start * \param tsc_end timestamp of end * * \return elaped cycles */ cycles_t bench_time_diff(cycles_t tsc_start, cycles_t tsc_end) { if (!bench_is_initialized) { bench_init(); } cycles_t result; if (tsc_end < tsc_start) { result = (LONG_MAX - tsc_start) + tsc_end - bench_tscoverhead(); } else { result = (tsc_end - tsc_start - bench_tscoverhead()); } return result; }
static void test(char *base, size_t size, size_t runs, reset_fn reset, measure_fn measure, const char *name) { assert(size % sizeof(struct cte) == 0); struct cte *ctes = (struct cte*)base; size_t num_caps = size/sizeof(struct cte); int run, skipped; for (run = skipped = 0; run < runs && (skipped < runs/10 || skipped < run*2); run++) { // reset MDB reset(base, size); // perform measurement cycles_t val = measure(ctes, num_caps); if (!val) { // measurement skipped printf("%s: skipping\n", name); skipped++; run--; continue; } // output printf("%s: %"PRIu64"/%lu\n", name, val - bench_tscoverhead(), num_caps); } if (run < runs) { printf("%s: skipped too many, aborting\n", name); } }
void experiment(coreid_t idx) { timestamps = malloc(sizeof(struct timestamps) * MAX_COUNT); assert(timestamps != NULL); struct bench_ump_binding *bu = (struct bench_ump_binding*)array[idx]; struct flounder_ump_state *fus = &bu->ump_state; struct ump_chan *chan = &fus->chan; struct ump_chan_state *send = &chan->send_chan; struct ump_chan_state *recv = &chan->endpoint.chan; printf("Running latency between core %"PRIuCOREID" and core %"PRIuCOREID"\n", my_core_id, idx); /* Run experiment */ for (int i = 0; i < MAX_COUNT; i++) { volatile struct ump_message *msg; struct ump_control ctrl; timestamps[i].time0 = bench_tsc(); msg = ump_impl_get_next(send, &ctrl); msg->header.control = ctrl; while (!ump_impl_recv(recv)); timestamps[i].time1 = bench_tsc(); } /* Print results */ for (int i = MAX_COUNT / 10; i < MAX_COUNT; i++) { if (timestamps[i].time1 > timestamps[i].time0) { printf("page %d took %"PRIuCYCLES"\n", i, timestamps[i].time1 - bench_tscoverhead() - timestamps[i].time0); } } }
static void start_experiment(void) { errval_t err; for (int i = 1; i < num_cores; i++) { int count = 0; experiment_flag = false; experiment_count = i; for (int j = 0; j < MAX_CPUS; j++) { if (array[j]) { while(1) { err = array[j]->tx_vtbl.shmc_start(array[j], NOP_CONT); if (err_is_ok(err)) { break; } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { messages_wait_and_handle_next(); } else { USER_PANIC_ERR(err, "sending shmc_start failed"); } } count++; if (count == i) { break; } } } run_experiment(); printf("Running on %d cores\n", i + 1); for (int j = 0; j < MAX_COUNT; j++) { printf("page %d took %"PRIuCYCLES"\n", j, timestamps[j].time1 - timestamps[j].time0 - bench_tscoverhead()); } while(!experiment_flag) { messages_wait_and_handle_next(); } } printf("client done\n"); }
// continue experiment static void experiment_cont(void* arg) { errval_t err; static bool flag = false; static int message_type = 0; // Experiment finished (with this message type) if (i == MAX_COUNT - 1) { #if CONFIG_TRACE #else // print measured times for (int j = MAX_COUNT / 10; j < MAX_COUNT; j++) { printf( "page %d took %"PRIuCYCLES"\n", j, timestamps[j].time1 - bench_tscoverhead() - timestamps[j].time0); } #endif // go to next message type message_type++; flag = false; i = 0; if (message_type > 13) { // stop tracing err = trace_event(TRACE_SUBSYS_MULTIHOP, TRACE_EVENT_MULTIHOP_BENCH_STOP, 0); if (err_is_fail(err)) { USER_PANIC_ERR(err, "trace_event failed"); } #if CONFIG_TRACE // dump trace char *buf = malloc(50*4096*4096); size_t length = trace_dump(buf, 20*4096*4096, NULL); printf("%s\n", buf); printf("length of buffer %lu\n", length); #endif printf("client done!\n"); return; } } if (!flag) { // Start experiment #if CONFIG_TRACE #else printf("Running latency test for message %s...\n", get_message_name(message_type)); #endif flag = true; timestamps[i].time0 = bench_tsc(); } else { // Continue experiment i++; timestamps[i].time0 = bench_tsc(); } // trace send event err = trace_event(TRACE_SUBSYS_MULTIHOP, TRACE_EVENT_MULTIHOP_MESSAGE_SEND, message_type); if (err_is_fail(err)) { USER_PANIC_ERR(err, "trace_event failed"); } // send next message switch (message_type) { case 0: err = binding->tx_vtbl.fsb_empty_request(binding, NOP_CONT); break; case 1: err = binding->tx_vtbl.fsb_payload32_1_request(binding, NOP_CONT, 1); break; case 2: err = binding->tx_vtbl.fsb_payload32_2_request(binding, NOP_CONT, 1, 2); break; case 3: err = binding->tx_vtbl.fsb_payload32_4_request(binding, NOP_CONT, 1, 2, 3, 4); break; case 4: err = binding->tx_vtbl.fsb_payload32_8_request(binding, NOP_CONT, 1, 2, 3, 4, 5, 6, 7, 8); break; case 5: err = binding->tx_vtbl.fsb_payload32_16_request(binding, NOP_CONT, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); break; case 6: err = binding->tx_vtbl.fsb_payload64_1_request(binding, NOP_CONT, 1); break; case 7: err = binding->tx_vtbl.fsb_payload64_2_request(binding, NOP_CONT, 1, 2); break; case 8: err = binding->tx_vtbl.fsb_payload64_4_request(binding, NOP_CONT, 1, 2, 3, 4); break; case 9: err = binding->tx_vtbl.fsb_payload64_8_request(binding, NOP_CONT, 1, 2, 3, 4, 5, 6, 7, 8); break; case 10: err = binding->tx_vtbl.fsb_payload64_16_request(binding, NOP_CONT, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); break; case 11: err = binding->tx_vtbl.fsb_buffer_request(binding, NOP_CONT, &buffer, 1); break; case 12: err = binding->tx_vtbl.fsb_buffer_request(binding, NOP_CONT, buffer2, 100); break; case 13: err = binding->tx_vtbl.fsb_buffer_request(binding, NOP_CONT, buffer3, 1000); break; default: printf("unknown message type\n"); abort(); break; } // make sure send was successful if (err_is_fail(err)) { USER_PANIC_ERR(err, "while running experiment\n"); } // receive reply (by dispatching events from the // waitset we use for the benchmark) while (reply_received == false) { event_dispatch(&signal_waitset); } experiment(); }