Statistics
| Branch: | Revision:

root / simpletrace.c @ 26f7227b

History | View | Annotate | Download (3.6 kB)

1
/*
2
 * Simple trace backend
3
 *
4
 * Copyright IBM, Corp. 2010
5
 *
6
 * This work is licensed under the terms of the GNU GPL, version 2.  See
7
 * the COPYING file in the top-level directory.
8
 *
9
 */
10

    
11
#include <stdlib.h>
12
#include <stdint.h>
13
#include <stdio.h>
14
#include <time.h>
15
#include "trace.h"
16

    
17
/** Trace file header event ID */
18
#define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */
19

    
20
/** Trace file magic number */
21
#define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
22

    
23
/** Trace file version number, bump if format changes */
24
#define HEADER_VERSION 0
25

    
26
/** Trace buffer entry */
27
typedef struct {
28
    uint64_t event;
29
    uint64_t timestamp_ns;
30
    uint64_t x1;
31
    uint64_t x2;
32
    uint64_t x3;
33
    uint64_t x4;
34
    uint64_t x5;
35
    uint64_t x6;
36
} TraceRecord;
37

    
38
enum {
39
    TRACE_BUF_LEN = 64 * 1024 / sizeof(TraceRecord),
40
};
41

    
42
static TraceRecord trace_buf[TRACE_BUF_LEN];
43
static unsigned int trace_idx;
44
static FILE *trace_fp;
45

    
46
static bool write_header(FILE *fp)
47
{
48
    static const TraceRecord header = {
49
        .event = HEADER_EVENT_ID,
50
        .timestamp_ns = HEADER_MAGIC,
51
        .x1 = HEADER_VERSION,
52
    };
53

    
54
    return fwrite(&header, sizeof header, 1, fp) == 1;
55
}
56

    
57
static void flush_trace_buffer(void)
58
{
59
    if (!trace_fp) {
60
        trace_fp = fopen("trace.log", "w");
61
        if (trace_fp) {
62
            write_header(trace_fp);
63
        }
64
    }
65
    if (trace_fp) {
66
        size_t unused; /* for when fwrite(3) is declared warn_unused_result */
67
        unused = fwrite(trace_buf, trace_idx * sizeof(trace_buf[0]), 1, trace_fp);
68
    }
69

    
70
    /* Discard written trace records */
71
    trace_idx = 0;
72
}
73

    
74
void st_set_trace_file_enabled(bool enable)
75
{
76
    if (enable == trace_file_enabled) {
77
        return; /* no change */
78
    }
79

    
80
    /* Flush/discard trace buffer */
81
    st_flush_trace_buffer();
82

    
83
    /* To disable, close trace file */
84
    if (!enable) {
85
        fclose(trace_fp);
86
        trace_fp = NULL;
87
    }
88

    
89
    trace_file_enabled = enable;
90
}
91

    
92
static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
93
                  uint64_t x4, uint64_t x5, uint64_t x6)
94
{
95
    TraceRecord *rec = &trace_buf[trace_idx];
96
    struct timespec ts;
97

    
98
    /* TODO Windows?  It would be good to use qemu-timer here but that isn't
99
     * linked into qemu-tools.  Also we should avoid recursion in the tracing
100
     * code, therefore it is useful to be self-contained.
101
     */
102
    clock_gettime(CLOCK_MONOTONIC, &ts);
103

    
104
    rec->event = event;
105
    rec->timestamp_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec;
106
    rec->x1 = x1;
107
    rec->x2 = x2;
108
    rec->x3 = x3;
109
    rec->x4 = x4;
110
    rec->x5 = x5;
111
    rec->x6 = x6;
112

    
113
    if (++trace_idx == TRACE_BUF_LEN) {
114
        flush_trace_buffer();
115
    }
116
}
117

    
118
void trace0(TraceEventID event)
119
{
120
    trace(event, 0, 0, 0, 0, 0, 0);
121
}
122

    
123
void trace1(TraceEventID event, uint64_t x1)
124
{
125
    trace(event, x1, 0, 0, 0, 0, 0);
126
}
127

    
128
void trace2(TraceEventID event, uint64_t x1, uint64_t x2)
129
{
130
    trace(event, x1, x2, 0, 0, 0, 0);
131
}
132

    
133
void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3)
134
{
135
    trace(event, x1, x2, x3, 0, 0, 0);
136
}
137

    
138
void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4)
139
{
140
    trace(event, x1, x2, x3, x4, 0, 0);
141
}
142

    
143
void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5)
144
{
145
    trace(event, x1, x2, x3, x4, x5, 0);
146
}
147

    
148
void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6)
149
{
150
    trace(event, x1, x2, x3, x4, x5, x6);
151
}
152

    
153
/**
154
 * Flush the trace buffer on exit
155
 */
156
static void __attribute__((constructor)) st_init(void)
157
{
158
    atexit(st_flush_trace_buffer);
159
}