Compile bfscope for armv5 and exvlude bench for armv5.
[barrelfish] / usr / bfscope / bfscope.c
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, Haldeneggsteig 4, 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
44 extern struct waitset *lwip_waitset;
45
46 static char *trace_buf = NULL;
47 static size_t trace_length = 0;
48 static size_t trace_sent = 0;
49 static bool dump_in_progress = false;
50
51 /// Timestamp when the sending of a trace dump over the network started
52 static uint64_t timestamp_start = 0;
53
54 /// The client that connected to this bfscope instance.
55 static 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.
59 static bool local_flush = false;
60
61
62 #define DEBUG if (0) printf
63
64 static void bfscope_send_flush_ack_to_monitor(void);
65
66 /*
67  * \brief Close the specified TCP connection
68  */
69 static 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  */
82 static 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  */
96 static 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  */
113 static 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  */
155 static 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  */
170 static 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  */
195 static 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  */
207 static 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  */
241 static 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  */
279 static 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  */
302 static 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  */
334 static 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
341 struct bfscope_ack_send_state {
342     struct event_queue_node qnode;
343     struct monitor_binding *monitor_binding;
344 };
345
346 static 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  */
371 static 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
386 static 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
401 static 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
410 int 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