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