1/** 2 * \file 3 * \brief Tracing support for the monitor. 4 */ 5 6/* 7 * Copyright (c) 2012 ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <barrelfish/barrelfish.h> 16#include <barrelfish/nameservice_client.h> 17#include <barrelfish/event_queue.h> 18#include <barrelfish/dispatcher_arch.h> 19#include <trace/trace.h> 20#include <sys/time.h> 21#include "monitor.h" 22 23static void trace_intermon_send_time_measurement_request(struct intermon_binding *ib, struct intermon_msg_queue_elem *elem); 24static void trace_intermon_send_time_measurement_ack(struct intermon_binding *ib, struct intermon_msg_queue_elem *elem); 25 26static void trace_intermon_send_prepare(struct intermon_binding *ib, struct intermon_msg_queue_elem *elem); 27static void trace_intermon_notify_next_core(coreid_t origin_core); 28static void trace_intermon_send_prepare_finished(struct intermon_binding *ib, struct intermon_msg_queue_elem *elem); 29static void trace_monitor_send_prepare_finish(struct monitor_binding *mb, struct monitor_msg_queue_elem *elem); 30static void trace_monitor_prepare_finished_successfully(void *arg); 31 32// Global variables for communication with initiator program 33static struct monitor_binding *initiator_to_monitor_binding; 34static struct monitor_msg_queue_elem *initiator_monitor_elem; 35 36//------------------------------------------------------------------------------ 37// Time measurement 38//------------------------------------------------------------------------------ 39 40struct trace_measure_time_state { 41 struct intermon_msg_queue_elem elem; 42 coreid_t origin_core; 43 uint64_t t0; 44 uint64_t t1; 45}; 46 47/* 48 * Perform a time measurement, relative to core 0. 49 */ 50static void trace_monitor_measure_time(coreid_t origin_core) 51{ 52 printf("trace_monitor_measure_time on core: %d\n", my_core_id); 53 54 if(my_core_id == 0) { 55 56 dispatcher_handle_t handle = curdispatcher(); 57 struct dispatcher_generic *disp = get_dispatcher_generic(handle); 58 struct trace_buffer *trace_buf = disp->trace_buf; 59 60 trace_buf->t_offset = 0; 61 62 // Notify next core 63 trace_intermon_notify_next_core(origin_core); 64 65 } else { 66 67 // Measure time relative to core 0 68 69 // TODO implement 70 71 struct trace_measure_time_state *state = malloc(sizeof(struct trace_measure_time_state)); 72 73 struct intermon_binding *ib; 74 errval_t err = intermon_binding_get(0, &ib); 75 assert(err_is_ok(err)); 76 77 state->elem.cont = trace_intermon_send_time_measurement_request; 78 state->origin_core = origin_core; 79 80 trace_intermon_send_time_measurement_request(ib, &state->elem); 81 82 } 83} 84 85/* 86 * Send a time measurement request to core 0. 87 */ 88static void trace_intermon_send_time_measurement_request(struct intermon_binding *ib, struct intermon_msg_queue_elem *elem) 89{ 90 errval_t err; 91 92 struct trace_measure_time_state *state = (struct trace_measure_time_state*) elem; 93 94 err = ib->tx_vtbl.trace_measure(ib, MKCONT(free, state), state->origin_core, rdtsc()); 95 96 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 97 // Sending failed, so it must be repeated 98 struct intermon_state *ist = ib->st; 99 err = intermon_enqueue_send(ib, &ist->queue, get_default_waitset(), &state->elem.queue); 100 assert(err_is_ok(err)); 101 } else if(err_is_fail(err)) { 102 USER_PANIC_ERR(err, "Sending trace_intermon_send_time_measurement_request failed"); 103 // TODO error handling 104 } // Else: Everything is ok, do nothing 105 106 107} 108 109/* 110 * We received a message for a time measurement. 111 */ 112static void trace_intermon_measure_recv(struct intermon_binding *ib, coreid_t origin_core, uint64_t t0) 113{ 114 // All measurements are relative to core 0, thus this monitor must be running 115 // on core 0. 116 assert(my_core_id == 0); 117 118 uint64_t t1 = rdtsc(); 119 120 struct trace_measure_time_state *state = malloc(sizeof(struct trace_measure_time_state)); 121 122 state->elem.cont = trace_intermon_send_time_measurement_ack; 123 state->origin_core = origin_core; 124 state->t0 = t0; 125 state->t1 = t1; 126 127 trace_intermon_send_time_measurement_ack(ib, &state->elem); 128} 129 130/* 131 * Send a time measurement back to the core who started the time measurement. 132 */ 133static void trace_intermon_send_time_measurement_ack(struct intermon_binding *ib, struct intermon_msg_queue_elem *elem) 134{ 135 errval_t err; 136 137 struct trace_measure_time_state *state = (struct trace_measure_time_state*) elem; 138 139 err = ib->tx_vtbl.trace_measure_ack(ib, MKCONT(free, state), state->origin_core, state->t0, state->t1, rdtsc()); 140 141 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 142 // Sending failed, so it must be repeated 143 struct intermon_state *ist = ib->st; 144 err = intermon_enqueue_send(ib, &ist->queue, get_default_waitset(), &state->elem.queue); 145 assert(err_is_ok(err)); 146 } else if(err_is_fail(err)) { 147 USER_PANIC_ERR(err, "Sending trace_intermon_send_time_measurement_ack failed"); 148 // TODO error handling 149 } // Else: Everything is ok, do nothing 150 151 152} 153 154/* 155 * The monitor who started a time measurement received the response from core 0. 156 */ 157static void trace_intermon_measure_ack_recv(struct intermon_binding* ib, coreid_t origin_core, uint64_t t0, uint64_t t1, uint64_t t2) 158{ 159 uint64_t t3 = rdtsc(); 160 161 printf("NTP result: %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", t0,t1,t2,t3); 162 163 // Network Time Protocol formula 164 int64_t offset = (((t1-t0)+(t2-t3))/2); 165 166 dispatcher_handle_t handle = curdispatcher(); 167 struct dispatcher_generic *disp = get_dispatcher_generic(handle); 168 struct trace_buffer *trace_buf = disp->trace_buf; 169 170 trace_buf->t_offset = offset; 171 172 // Notify next core 173 trace_intermon_notify_next_core(origin_core); 174} 175 176//------------------------------------------------------------------------------ 177// Intermonitor Communication for Preparation 178//------------------------------------------------------------------------------ 179 180struct trace_prepare_state { 181 struct intermon_msg_queue_elem elem; 182 coreid_t origin_core; 183}; 184 185/* 186 * Notify either the next core to send prepare, or if there is no next core, 187 * notify the origin core that the preparation is finished. 188 */ 189static void trace_intermon_notify_next_core(coreid_t origin_core) 190{ 191 coreid_t next_core = my_core_id; 192 193 struct trace_prepare_state *state = malloc(sizeof (struct trace_prepare_state)); 194 state->origin_core = origin_core; 195 state->elem.cont = trace_intermon_send_prepare; 196 197 bool has_more_cores = true; 198 errval_t err = SYS_ERR_OK; 199 200 struct intermon_binding *ib; 201 202 // Search for the next core to send the prepare message to 203 do { 204 205 if (next_core == MAX_COREID) { 206 // There are no more cores to notify 207 has_more_cores = false; 208 break; 209 } 210 211 next_core++; 212 213 err = intermon_binding_get(next_core, &ib); 214 215 } while(err_is_fail(err)); 216 217 218 if (has_more_cores) { 219 // There is a another core 220 221 assert(ib != NULL); 222 assert(next_core <= MAX_COREID); 223 224 printf("Sending a prepare to core: %d\n", next_core); 225 226 trace_intermon_send_prepare(ib, &state->elem); 227 228 } else { 229 // There is no more core, notify the origin core 230 231 if (my_core_id == origin_core) { 232 // We are the origin core, just notify the user program 233 234 assert(initiator_to_monitor_binding != NULL); 235 236 initiator_monitor_elem = malloc(sizeof(struct monitor_msg_queue_elem)); 237 initiator_monitor_elem->cont = trace_monitor_send_prepare_finish; 238 239 trace_monitor_send_prepare_finish(initiator_to_monitor_binding, initiator_monitor_elem); 240 241 } else { 242 // Notify the monitor on the core on which the initiator is running 243 244 err = intermon_binding_get(origin_core, &ib); 245 246 assert(err_is_ok(err)); 247 248 struct intermon_msg_queue_elem *elem = malloc(sizeof(struct intermon_msg_queue_elem)); 249 250 trace_intermon_send_prepare_finished(ib, elem); 251 252 } 253 254 } 255 256} 257 258/* 259 * Send a message from a monitor to the monitor on which the initiator is running, 260 * to tell the monitor that it should tell the initiator that the preparation is 261 * finished. 262 */ 263static void trace_intermon_send_prepare_finished(struct intermon_binding *ib, struct intermon_msg_queue_elem *elem) 264{ 265 errval_t err; 266 267 err = ib->tx_vtbl.trace_prepare_finished(ib, MKCONT(free, elem)); 268 269 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 270 // Sending failed, so it must be repeated 271 struct intermon_state *ist = ib->st; 272 err = intermon_enqueue_send(ib, &ist->queue, get_default_waitset(), &elem->queue); 273 assert(err_is_ok(err)); 274 } else if(err_is_fail(err)) { 275 USER_PANIC_ERR(err, "Sending trace_prepare_finished failed"); 276 // TODO error handling 277 } // Else: Everything is ok, do nothing 278 279 280} 281 282/* 283 * The monitor on which the initiator is running received a message from a 284 * different monitor, telling it that the preparation is finished. Forward this 285 * information to the user program. 286 */ 287static void trace_intermon_prepare_finished_recv(struct intermon_binding *ib) 288{ 289 assert(initiator_to_monitor_binding != NULL); 290 291 initiator_monitor_elem = malloc(sizeof(struct monitor_msg_queue_elem)); 292 initiator_monitor_elem->cont = trace_monitor_send_prepare_finish; 293 294 trace_monitor_send_prepare_finish(initiator_to_monitor_binding, initiator_monitor_elem); 295} 296 297/* 298 * Send a prepare message to the next monitor. 299 */ 300static void trace_intermon_send_prepare(struct intermon_binding *ib, struct intermon_msg_queue_elem *elem) 301{ 302 errval_t err; 303 304 struct trace_prepare_state *state = (struct trace_prepare_state*) elem; 305 306 err = ib->tx_vtbl.trace_prepare(ib, MKCONT(free, state), state->origin_core); 307 308 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 309 // Sending failed, so it must be repeated 310 printf("trace_intermon_send_prepare flounder busy\n"); 311 struct intermon_state *ist = ib->st; 312 err = intermon_enqueue_send(ib, &ist->queue, 313 get_default_waitset(), &state->elem.queue); 314 assert(err_is_ok(err)); 315 } else if(err_is_fail(err)) { 316 USER_PANIC_ERR(err, "Sending trace prepare failed"); 317 // TODO error handling 318 } // Else: Everything is ok, do nothing 319 320} 321 322/* 323 * This monitor has received a prepare message. 324 */ 325static void trace_intermon_prepare_recv(struct intermon_binding *ib, coreid_t origin_core) 326{ 327 trace_monitor_measure_time(origin_core); 328} 329 330//------------------------------------------------------------------------------ 331// Monitor communicating with user program 332//------------------------------------------------------------------------------ 333 334/* 335 * This is the function that is invoked when we receive a prepare message from 336 * a user program. 337 */ 338static void trace_monitor_prepare_recv(struct monitor_binding *mb, coreid_t origin_core) 339{ 340 printf("trace_monitor_prepare_recv\n"); 341 342 initiator_to_monitor_binding = mb; 343 344 if (my_core_id == 0) { 345 // Perform time measurement, and notify next core afterwards 346 347 return trace_monitor_measure_time(origin_core); 348 } else { 349 // Notify core 0 to start measurement 350 351 struct trace_prepare_state *state = malloc(sizeof(struct trace_prepare_state)); 352 state->origin_core = origin_core; 353 state->elem.cont = trace_intermon_send_prepare; 354 355 struct intermon_binding *ib; 356 357 errval_t err = intermon_binding_get(0, &ib); 358 359 assert(err_is_ok(err)); 360 361 trace_intermon_send_prepare(ib, &state->elem); 362 } 363} 364 365/* 366 * This function sends the prepare_finished message from the monitor to the 367 * user program. 368 */ 369static void trace_monitor_send_prepare_finish(struct monitor_binding *mb, struct monitor_msg_queue_elem *elem) 370{ 371 372 errval_t err; 373 374 err = mb->tx_vtbl.trace_prepare_finished(mb, 375 MKCONT(trace_monitor_prepare_finished_successfully, NULL)); 376 377 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 378 // Sending failed, so it must be repeated 379 struct monitor_state *ist = mb->st; 380 err = monitor_enqueue_send(mb, &ist->queue, get_default_waitset(), &elem->queue); 381 assert(err_is_ok(err)); 382 } else if(err_is_fail(err)) { 383 USER_PANIC_ERR(err, "Sending trace_prepare_finished failed"); 384 // TODO error handling 385 } // Else: everything is ok, do nothing 386} 387 388/* 389 * This function is called to reset the state, once the preparation is finished. 390 */ 391static void trace_monitor_prepare_finished_successfully(void *arg) 392{ 393 free(initiator_monitor_elem); 394 initiator_monitor_elem = NULL; 395 initiator_to_monitor_binding = NULL; 396} 397 398//------------------------------------------------------------------------------ 399// Message Table Initialization 400//------------------------------------------------------------------------------ 401 402 403// set up receive vtable in the intermonitor interface 404errval_t trace_intermon_init(struct intermon_binding *ib) 405{ 406 ib->rx_vtbl.trace_prepare = &trace_intermon_prepare_recv; 407 ib->rx_vtbl.trace_prepare_finished = &trace_intermon_prepare_finished_recv; 408 ib->rx_vtbl.trace_measure = &trace_intermon_measure_recv; 409 ib->rx_vtbl.trace_measure_ack = &trace_intermon_measure_ack_recv; 410 411 return SYS_ERR_OK; 412} 413 414// set up receive vtable in the monitor interface 415errval_t trace_monitor_init(struct monitor_binding *mb) 416{ 417 mb->rx_vtbl.trace_prepare = &trace_monitor_prepare_recv; 418 419 return SYS_ERR_OK; 420} 421