-static bool get_trace_record(unsigned int idx, TraceRecord *record)
+static bool get_trace_record(unsigned int idx, TraceRecord **recordptr)
{
- if (!(trace_buf[idx].event& TRACE_RECORD_VALID)) {
+ uint8_t rec_hdr[sizeof(TraceRecord)];
+ uint64_t event_flag = 0;
+ TraceRecord *record = (TraceRecord *) rec_hdr;
+ /* read the event flag to see if its a valid record */
+ read_from_buffer(idx, rec_hdr, sizeof(event_flag));
+
+ if (!(record->event& TRACE_RECORD_VALID)) {
return false;
}
__sync_synchronize(); /* read memory barrier before accessing record */
-
- *record = trace_buf[idx];
- record->event&= ~TRACE_RECORD_VALID;
- return true;
+ /* read the record header to know record length */
+ read_from_buffer(idx, rec_hdr, sizeof(TraceRecord));
+ *recordptr = g_malloc(record->length);
+ /* make a copy of record to avoid being overwritten */
+ read_from_buffer(idx, (uint8_t *)*recordptr, record->length);
+ __sync_synchronize(); /* memory barrier before clearing valid flag */
+ (*recordptr)->event&= ~TRACE_RECORD_VALID;
+ /* reset record event validity flag on global trace buffer */
+ write_to_buffer(idx,&event_flag, sizeof(event_flag));
+ if ((*recordptr)->event< NR_TRACE_EVENTS) {
+ return true;
+ } else {
+ /* XXX: Ideally this should not happen, but its possible !
+ * See comments in trace_record_start for more details.
+ * We dont know where to start next and therefore resetting
+ * writeout_idx to trace_idx. Also, as we dont know how many
+ * events dropped in between, at least increment the count by one.
+ */
+ g_atomic_int_inc((gint *)&dropped_events);
+ g_free(*recordptr);
+ writeout_idx = trace_idx;
+ return false;
+ }
}
-void trace1(TraceEventID event, uint64_t x1)
+int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t
datasize)
{
- trace(event, x1, 0, 0, 0, 0, 0);
-}
+ unsigned int idx, rec_off, old_idx, new_idx;
+ uint32_t rec_len = sizeof(TraceRecord) + datasize;
+ uint64_t timestamp_ns = get_clock();
+
+ while (1) {
+ old_idx = trace_idx;
+ smp_rmb();
+ new_idx = old_idx + rec_len;
+
+ if (new_idx - writeout_idx> TRACE_BUF_LEN) {
+ /* Trace Buffer Full, Event dropped ! */
+ g_atomic_int_inc((gint *)&dropped_events);
+ return -ENOSPC;
+ }
-void trace2(TraceEventID event, uint64_t x1, uint64_t x2)
-{
- trace(event, x1, x2, 0, 0, 0, 0);
-}
+ /* XXX: If threads race here, take care in get_trace_record */
-void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3)
-{
- trace(event, x1, x2, x3, 0, 0, 0);
+ if (g_atomic_int_compare_and_exchange((gint *)&trace_idx,
+ old_idx, new_idx)) {
+ break;
+ }
+ }
+
+ idx = old_idx % TRACE_BUF_LEN;
+ /* To check later if threshold crossed */
+ rec->next_tbuf_idx = new_idx % TRACE_BUF_LEN;
+
+ rec_off = idx;
+ rec_off = write_to_buffer(rec_off, (uint8_t*)&event, sizeof(event));
+ rec_off = write_to_buffer(rec_off, (uint8_t*)×tamp_ns,
sizeof(timestamp_ns));
+ rec_off = write_to_buffer(rec_off, (uint8_t*)&rec_len, sizeof(rec_len));
+
+ rec->tbuf_idx = idx;
+ rec->rec_off = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN;
+ return 0;
}
-void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4)
+static void read_from_buffer(unsigned int idx, void *dataptr, size_t size)
{
- trace(event, x1, x2, x3, x4, 0, 0);
+ uint8_t *data_ptr = dataptr;
+ uint32_t x = 0;
+ while (x< size) {
+ if (idx>= TRACE_BUF_LEN) {
+ idx = idx % TRACE_BUF_LEN;
+ }
+ data_ptr[x++] = trace_buf[idx++];
+ }
}
-void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, uint64_t x5)
+static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t
size)
{
- trace(event, x1, x2, x3, x4, x5, 0);
+ uint8_t *data_ptr = dataptr;
+ uint32_t x = 0;
+ while (x< size) {
+ if (idx>= TRACE_BUF_LEN) {
+ idx = idx % TRACE_BUF_LEN;
+ }
+ trace_buf[idx++] = data_ptr[x++];
+ }
+ return idx; /* most callers wants to know where to write next */
}
-void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, uint64_t x5, uint64_t x6)
+void trace_record_finish(TraceBufferRecord *rec)
{
- trace(event, x1, x2, x3, x4, x5, x6);
+ uint8_t temp_rec[sizeof(TraceRecord)];
+ TraceRecord *record = (TraceRecord *) temp_rec;
+ read_from_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
+ __sync_synchronize(); /* write barrier before marking as valid */
+ record->event |= TRACE_RECORD_VALID;
+ write_to_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
+
+ if ((trace_idx> writeout_idx)&&
+ (trace_idx - writeout_idx)> TRACE_BUF_FLUSH_THRESHOLD) {
+ flush_trace_file(false);
+ } else if ((writeout_idx> trace_idx)&&
+ (trace_idx> TRACE_BUF_FLUSH_THRESHOLD)) {
+ /* if trace_idx rollover before writeout_idx */
+ flush_trace_file(false);
+ }
}
void st_set_trace_file_enabled(bool enable)
@@ -231,10 +304,11 @@ void st_set_trace_file_enabled(bool enable)
flush_trace_file(true);
if (enable) {
- static const TraceRecord header = {
- .event = HEADER_EVENT_ID,
- .timestamp_ns = HEADER_MAGIC,
- .x1 = HEADER_VERSION,
+ static const TraceRecordHeader header = {
+ .header_event_id = HEADER_EVENT_ID,
+ .header_magic = HEADER_MAGIC,
+ /* Older log readers will check for version at next location */
+ .header_version = HEADER_VERSION,
};
trace_fp = fopen(trace_file_name, "wb");
diff --git a/trace/simple.h b/trace/simple.h
index 6b5358c..6755e99 100644
--- a/trace/simple.h
+++ b/trace/simple.h
@@ -22,16 +22,39 @@ typedef struct {
bool state;
} TraceEvent;
-void trace0(TraceEventID event);
-void trace1(TraceEventID event, uint64_t x1);
-void trace2(TraceEventID event, uint64_t x1, uint64_t x2);
-void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3);
-void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4);
-void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, uint64_t x5);
-void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, uint64_t x5, uint64_t x6);
void st_print_trace_file_status(FILE *stream, fprintf_function stream_printf);
void st_set_trace_file_enabled(bool enable);
bool st_set_trace_file(const char *file);
void st_flush_trace_buffer(void);
+typedef struct {
+ unsigned int tbuf_idx;
+ unsigned int next_tbuf_idx;
+ unsigned int rec_off;
+} TraceBufferRecord;
+
+/**
+ * Initialize a trace record and claim space for it in the buffer
+ *
+ * @arglen number of bytes required for arguments
+ */
+int trace_record_start(TraceBufferRecord *rec, TraceEventID id, size_t arglen);
+
+/**
+ * Append a 64-bit argument to a trace record
+ */
+void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val);
+
+/**
+ * Append a string argument to a trace record
+ */
+void trace_record_write_str(TraceBufferRecord *rec, const char *s);
+
+/**
+ * Mark a trace record completed
+ *
+ * Don't append any more arguments to the trace record after calling this.
+ */
+void trace_record_finish(TraceBufferRecord *rec);
+
#endif /* TRACE_SIMPLE_H */