1/** 2 * \file 3 * \brief Barrelfish trace server, Version 2 4 */ 5 6/* 7 * Copyright (c) 2007-2013, 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 <stdio.h> 16#include <stdlib.h> 17#include <errno.h> 18 19#include <barrelfish/barrelfish.h> 20#include <barrelfish/dispatch.h> 21#include <barrelfish/dispatcher_arch.h> 22#include <barrelfish/lmp_endpoints.h> 23#include <barrelfish/event_queue.h> 24#include <barrelfish/nameservice_client.h> 25#include <trace/trace.h> 26 27#include <flounder/flounder.h> 28#include <if/monitor_defs.h> 29 30#include <if/empty_defs.h> 31 32/* LWIP Network stack includes */ 33#include <lwip/init.h> 34#include <lwip/netif.h> 35#include <lwip/dhcp.h> 36#include <lwip/tcp.h> 37#include <netif/bfeth.h> 38#include <netif/etharp.h> 39 40#define BFSCOPE_TCP_PORT 6666 41 42#define BFSCOPE_BUFLEN (2<<20) 43 44extern struct waitset *lwip_waitset; 45 46static char *trace_buf = NULL; 47static size_t trace_length = 0; 48static size_t trace_sent = 0; 49static bool dump_in_progress = false; 50 51/// Timestamp when the sending of a trace dump over the network started 52static uint64_t timestamp_start = 0; 53 54/// The client that connected to this bfscope instance. 55static struct tcp_pcb *bfscope_client = NULL; 56 57/// If we are in autoflush is enabled, bfscope can itself determine to flush. In 58/// that case, we don't want to notify anyone after doing a locally initiated flush. 59static bool local_flush = false; 60 61 62#define DEBUG if (0) printf 63 64static void bfscope_send_flush_ack_to_monitor(void); 65 66/* 67 * \brief Close the specified TCP connection 68 */ 69static void bfscope_connection_close(struct tcp_pcb *tpcb) 70{ 71 DEBUG("bfscope: close\n"); 72 printf("%s:%s:%d:\n", __FILE__, __FUNCTION__, __LINE__); 73 trace_length = 0; 74 //tcp_arg(tpcb, NULL); 75 //tcp_close(tpcb); 76 //bfscope_client = NULL; 77} 78 79/* 80 * \brief Error callback from lwip 81 */ 82static void error_cb(void *arg, err_t err) 83{ 84 struct tcp_pcb *tpcb = (struct tcp_pcb *)arg; 85 86 printf("bfscope: TCP(%p) error %d\n", arg, err); 87 88 if (tpcb) { 89 bfscope_connection_close(tpcb); 90 } 91} 92 93/* 94 * Call this method when you finished dumping the current trace buffer. 95 */ 96static void bfscope_trace_dump_finished(void) 97{ 98 trace_length = 0; 99 trace_sent = 0; 100 dump_in_progress = false; 101 102 if (!local_flush) { 103 bfscope_send_flush_ack_to_monitor(); 104 } else { 105 // Locally initiated flush is finished. 106 local_flush = false; 107 } 108} 109 110/* 111 * \brief Send the next chunk of trace data down given TCP connection 112 */ 113static void bfscope_trace_send(struct tcp_pcb *tpcb) 114{ 115 char *bufptr; 116 int len; 117 118 //DEBUG("tcp_sndbuf=%d\n", tcp_sndbuf(tpcb)); 119 120 bufptr = trace_buf + trace_sent; 121 len = trace_length - trace_sent; 122 123 int more = 0; 124 if (len > tcp_sndbuf(tpcb)) { 125 len = tcp_sndbuf(tpcb); 126 more = 1; 127 } 128 129 /* Give the data to LWIP until it runs out of buffer space */ 130 err_t lwip_err = tcp_write(tpcb, bufptr, len, 131 TCP_WRITE_FLAG_COPY | (more ? TCP_WRITE_FLAG_MORE : 0)); 132 133 //DEBUG("%d %ld+%d\n", r, trace_sent, len); 134 135 if (lwip_err == ERR_MEM) { 136 printf("bfscope: lwip: out of memory\n"); 137 return; 138 } 139 140 trace_sent += len; 141 142 if (trace_sent >= trace_length) { 143 /* No more events */ 144 uint64_t timestamp_stop = rdtsc(); 145 DEBUG("bfscope: done (%zx bytes) in %"PRIuCYCLES" cycles\n", 146 trace_sent, timestamp_stop - timestamp_start); 147 148 bfscope_trace_dump_finished(); 149 } 150} 151 152/* 153 * \brief Callback from LWIP when each chunk of data has been sent 154 */ 155static err_t send_cb(void *arg, struct tcp_pcb *tpcb, u16_t length) 156{ 157 //printf("send_cb %d\n", length); 158 159 /* If we haven't finished sending the trace, then send more data */ 160 if (trace_length) { 161 bfscope_trace_send(tpcb); 162 } 163 164 return ERR_OK; 165} 166 167/* 168 * \brief This method should be called when a trace should be dumped on the network. 169 */ 170static void bfscope_trace_dump_network(void) 171{ 172 assert(bfscope_client != NULL); 173 assert(trace_length > 0); 174 175 printf("bfscope: sending %zu bytes to network...\n", trace_length); 176 177 /* Send length field */ 178 char tmpbuf[10]; 179 int len; 180 len = snprintf(tmpbuf, 9, "%zu", trace_length); 181 tcp_write(bfscope_client, tmpbuf, 8, TCP_WRITE_FLAG_COPY); 182 183 /* Start to send the trace */ 184 timestamp_start = rdtsc(); 185 trace_sent = 0; 186 187 bfscope_trace_send(bfscope_client); 188 189 tcp_output(bfscope_client); 190} 191 192/* 193 * \brief This method should be called when a trace should be dumped on the console. 194 */ 195static void bfscope_trace_dump_console(void) 196{ 197 printf("%s\n", trace_buf); 198 199 bfscope_trace_dump_finished(); 200} 201 202/* 203 * \brief This method should be called when a trace should be dumped. 204 * 205 * (Based upon a different application calling trace_flush() or so.) 206 */ 207static void bfscope_trace_dump(void) 208{ 209 if(dump_in_progress) { 210 // Currently there is already a dump in progress, do nothing. 211 return; 212 } 213 214 int number_of_events = 0; 215 // Acquire the trace buffer 216 trace_length = trace_dump(trace_buf, BFSCOPE_BUFLEN, &number_of_events); 217 218 DEBUG("bfscope: trace length %zu, nr. of events %d\n", trace_length, number_of_events); 219 220 if (trace_length <= 0 || number_of_events <= 0) { 221 DEBUG("bfscope: trace length too small, not dumping.\n"); 222 return; 223 } 224 225 dump_in_progress = true; 226 227 printf("%s:%s:%d: bfscope_client=%p\n", 228 __FILE__, __FUNCTION__, __LINE__, bfscope_client); 229 if (bfscope_client != NULL) { 230 // We have a connected client, dump to network 231 bfscope_trace_dump_network(); 232 } else { 233 // There is no client, just dump to console 234 bfscope_trace_dump_console(); 235 } 236} 237 238/* 239 * \brief Callback from LWIP when we receive TCP data 240 */ 241static err_t recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, 242 err_t err) 243{ 244 if (p == NULL) { 245 // close the connection 246 bfscope_connection_close(tpcb); 247 return ERR_OK; 248 } 249 250 /* don't send an immediate ack here, do it later with the data */ 251 tpcb->flags |= TF_ACK_DELAY; 252 253 assert(p->next == 0); 254 255 256 if ((p->tot_len > 2) && (p->tot_len < 200)) { 257 if (strncmp(p->payload, "trace", strlen("trace")) == 0) { 258 259 DEBUG("bfscope: trace request\n"); 260 261 // NOOP 262 263 } else { 264 DEBUG("bfscope: could not understand request\n"); 265 } 266 } 267 268 269 /* Done with the incoming data */ 270 tcp_recved(tpcb, p->len); 271 pbuf_free(p); 272 273 return ERR_OK; 274} 275 276/* 277 * \brief Callback from LWIP when a client connects to our TCP listen sock 278 */ 279static err_t accept_cb(void *arg, struct tcp_pcb *tpcb, err_t err) 280{ 281 printf("bfscope: connected\n"); 282 283 assert(err == ERR_OK); 284 285 tcp_recv(tpcb, recv_cb); 286 tcp_sent(tpcb, send_cb); 287 tcp_err(tpcb, error_cb); 288 tcp_arg(tpcb, (void*)tpcb); 289 290 tcp_accepted(tpcb); 291 292 293 bfscope_client = tpcb; 294 printf("%s:%s:%d: bfscope_client=%p\n", 295 __FILE__, __FUNCTION__, __LINE__, bfscope_client); 296 return ERR_OK; 297} 298 299/* 300 * \brief Start listening on the bfscope server port 301 */ 302static err_t bfscope_server_init(void) 303{ 304 err_t err; 305 306 uint16_t bind_port = BFSCOPE_TCP_PORT; 307 308 struct tcp_pcb *pcb = tcp_new(); 309 if (pcb == NULL) { 310 return ERR_MEM; 311 } 312 313 err = tcp_bind(pcb, IP_ADDR_ANY, bind_port); 314 if(err != ERR_OK) { 315 return(err); 316 } 317 318 struct tcp_pcb *pcb2 = tcp_listen(pcb); 319 assert(pcb2 != NULL); 320 tcp_accept(pcb2, accept_cb); 321 322 printf("bfscope: listening on port %"PRIu16"\n", BFSCOPE_TCP_PORT); 323 324 return ERR_OK; 325} 326 327//------------------------------------------------------------------------------ 328// Monitor Messaging Interface 329//------------------------------------------------------------------------------ 330 331/* 332 * This function is called when we receive a flush message from our monitor. 333 */ 334static void bfscope_handle_flush_msg(struct monitor_binding *mb, iref_t iref) 335{ 336 printf("bfscope flush request message received!\n"); 337 338 bfscope_trace_dump(); 339} 340 341struct bfscope_ack_send_state { 342 struct event_queue_node qnode; 343 struct monitor_binding *monitor_binding; 344}; 345 346static void bfscope_send_flush_ack_cont(void* arg) 347{ 348 errval_t err; 349 350 struct bfscope_ack_send_state *state = (struct bfscope_ack_send_state*) arg; 351 struct monitor_binding *monitor_binding = state->monitor_binding; 352 353 err = monitor_binding->tx_vtbl.bfscope_flush_ack(monitor_binding, MKCONT(free, state)); 354 355 if (err_is_ok(err)) { 356 event_mutex_unlock(&monitor_binding->mutex); 357 } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 358 err = monitor_binding->register_send(monitor_binding, monitor_binding->waitset, MKCONT(&bfscope_send_flush_ack_cont, state)); 359 assert(err_is_ok(err)); 360 } else { 361 event_mutex_unlock(&monitor_binding->mutex); 362 //TODO: Error handling 363 USER_PANIC_ERR(err, "Could not send flush ack message to monitor of bfscope"); 364 } 365} 366 367/* 368 * Call this method when bfscope is done with flushing and wants to notify 369 * the initiator of the flush request. 370 */ 371static void bfscope_send_flush_ack_to_monitor(void) { 372 373 374 struct bfscope_ack_send_state *state = malloc(sizeof(struct bfscope_ack_send_state)); 375 //memset(state, 0, sizeof(struct trace_broadcast_start_state)); 376 377 state->monitor_binding = get_monitor_binding(); 378 379 event_mutex_enqueue_lock(&state->monitor_binding->mutex, &state->qnode, MKCLOSURE(&bfscope_send_flush_ack_cont, state)); 380} 381 382//------------------------------------------------------------------------------ 383// Interface Exporting 384//------------------------------------------------------------------------------ 385 386static void export_cb(void *st, errval_t err, iref_t iref) 387{ 388 if (err_is_fail(err)) { 389 USER_PANIC_ERR(err, "export failed"); 390 } 391 392 printf("bfscope: exported at iref %"PRIuIREF"\n", iref); 393 394 // register this iref with the name service 395 err = nameservice_register("bfscope", iref); 396 if (err_is_fail(err)) { 397 USER_PANIC_ERR(err, "nameservice_register failed"); 398 } 399} 400 401static errval_t connect_cb(void *st, struct empty_binding *b) 402{ 403 USER_PANIC("bfscope: connect_cb got called"); 404} 405 406//------------------------------------------------------------------------------ 407// Main 408//------------------------------------------------------------------------------ 409 410int main(int argc, char**argv) 411{ 412 413#ifndef CONFIG_TRACE 414 // bail - no tracing support 415 printf("%.*s: Error, no tracing support, cannot start bfscope\n", 416 DISP_NAME_LEN, disp_name()); 417 printf("%.*s: recompile with trace = TRUE in build/hake/Config.hs\n", 418 DISP_NAME_LEN, disp_name()); 419 return -1; 420#endif 421 422 // Allocate the outgoing buffer 423 if (trace_buf == NULL) { 424 trace_buf = malloc(BFSCOPE_BUFLEN); 425 } 426 assert(trace_buf); 427 428 /* Disable tracing for bfscope */ 429 dispatcher_handle_t handle = curdispatcher(); 430 struct dispatcher_generic *disp = get_dispatcher_generic(handle); 431 disp->trace_buf = NULL; 432 433 printf("%.*s running on core %d\n", DISP_NAME_LEN, disp_name(), 434 disp_get_core_id()); 435 436 /* Connect to e1000 driver */ 437 printf("%.*s: trying to connect to the e1000 driver...\n", 438 DISP_NAME_LEN, disp_name()); 439 440 lwip_init_auto(); 441 442 err_t lwip_err = bfscope_server_init(); 443 444 assert(lwip_err == ERR_OK); 445 446 447 // Export our empty interface 448 errval_t err; 449 err = empty_export(NULL /* state pointer for connect/export callbacks */, 450 export_cb, connect_cb, get_default_waitset(), 451 IDC_EXPORT_FLAGS_DEFAULT); 452 if (err_is_fail(err)) { 453 USER_PANIC_ERR(err, "export failed"); 454 } 455 456 // Register our message handlers with the monitor 457 struct monitor_binding *monitor_binding; 458 monitor_binding = get_monitor_binding(); 459 monitor_binding->rx_vtbl.bfscope_flush_send = &bfscope_handle_flush_msg; 460 461 462 while (1) { 463 //err = event_dispatch(lwip_waitset); 464 err = event_dispatch_non_block(lwip_waitset); 465 466 if (err == LIB_ERR_NO_EVENT) { 467 // It is ok that no event is dispatched. 468 err = ERR_OK; 469 } 470 471 DEBUG("bfscope: dispatched event, autoflush: %d\n",((struct trace_buffer*) trace_buffer_master)->autoflush); 472 473 // Check if we are in autoflush mode 474 if(((struct trace_buffer*) trace_buffer_master)->autoflush) { 475 local_flush = true; 476 bfscope_trace_dump(); 477 } 478 479 thread_yield_dispatcher(NULL_CAP); 480 481 482 if (err_is_fail(err)) { 483 DEBUG_ERR(err, "in event_dispatch"); 484 break; 485 } 486 } 487 488 return 0; 489} 490 491