~fboudra/qemu-linaro/new-upstream-release-1.2.0-2012.09-0ubuntu1

« back to all changes in this revision

Viewing changes to trace/simple.c

  • Committer: Fathi Boudra
  • Author(s): Fathi Boudra
  • Date: 2012-08-21 06:47:11 UTC
  • mfrom: (0.1.16)
  • Revision ID: fathi.boudra@linaro.org-20120821064711-7yxmubp2v8a44xce
Tags: 1.1.50-2012.08-0ubuntu1
* New upstream release.
  - support emulated systems with more than 2G of memory. (LP: #1030588)
* Drop powerpc-missing-include.patch - merged upstream.
* Update debian/control: 
  - drop perl build dependency.
  - add libfdt-dev build dependency.
* Update debian/qemu-keymaps.install file.
* Update debian/rules:
  - update QEMU_CPU for ARM architecture: armv4l -> armv7l.
  - update conf_audio_drv: default to PulseAudio since PA is the default on
    Ubuntu.
  - enable KVM on ARM architecture.
  - enable flat device tree support (--enable-fdt). (LP: #1030594)

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
#define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
28
28
 
29
29
/** Trace file version number, bump if format changes */
30
 
#define HEADER_VERSION 0
 
30
#define HEADER_VERSION 2
31
31
 
32
32
/** Records were dropped event ID */
33
33
#define DROPPED_EVENT_ID (~(uint64_t)0 - 1)
35
35
/** Trace record is valid */
36
36
#define TRACE_RECORD_VALID ((uint64_t)1 << 63)
37
37
 
38
 
/** Trace buffer entry */
39
 
typedef struct {
40
 
    uint64_t event;
41
 
    uint64_t timestamp_ns;
42
 
    uint64_t x1;
43
 
    uint64_t x2;
44
 
    uint64_t x3;
45
 
    uint64_t x4;
46
 
    uint64_t x5;
47
 
    uint64_t x6;
48
 
} TraceRecord;
49
 
 
50
 
enum {
51
 
    TRACE_BUF_LEN = 4096,
52
 
    TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4,
53
 
};
54
 
 
55
38
/*
56
39
 * Trace records are written out by a dedicated thread.  The thread waits for
57
40
 * records to become available, writes them out, and then waits again.
62
45
static bool trace_available;
63
46
static bool trace_writeout_enabled;
64
47
 
65
 
static TraceRecord trace_buf[TRACE_BUF_LEN];
 
48
enum {
 
49
    TRACE_BUF_LEN = 4096 * 64,
 
50
    TRACE_BUF_FLUSH_THRESHOLD = TRACE_BUF_LEN / 4,
 
51
};
 
52
 
 
53
uint8_t trace_buf[TRACE_BUF_LEN];
66
54
static unsigned int trace_idx;
 
55
static unsigned int writeout_idx;
 
56
static uint64_t dropped_events;
67
57
static FILE *trace_fp;
68
58
static char *trace_file_name = NULL;
69
59
 
 
60
/* * Trace buffer entry */
 
61
typedef struct {
 
62
    uint64_t event; /*   TraceEventID */
 
63
    uint64_t timestamp_ns;
 
64
    uint32_t length;   /*    in bytes */
 
65
    uint32_t reserved; /*    unused */
 
66
    uint8_t arguments[];
 
67
} TraceRecord;
 
68
 
 
69
typedef struct {
 
70
    uint64_t header_event_id; /* HEADER_EVENT_ID */
 
71
    uint64_t header_magic;    /* HEADER_MAGIC    */
 
72
    uint64_t header_version;  /* HEADER_VERSION  */
 
73
} TraceRecordHeader;
 
74
 
 
75
 
 
76
static void read_from_buffer(unsigned int idx, void *dataptr, size_t size);
 
77
static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size);
 
78
 
 
79
static void clear_buffer_range(unsigned int idx, size_t len)
 
80
{
 
81
    uint32_t num = 0;
 
82
    while (num < len) {
 
83
        if (idx >= TRACE_BUF_LEN) {
 
84
            idx = idx % TRACE_BUF_LEN;
 
85
        }
 
86
        trace_buf[idx++] = 0;
 
87
        num++;
 
88
    }
 
89
}
70
90
/**
71
91
 * Read a trace record from the trace buffer
72
92
 *
75
95
 *
76
96
 * Returns false if the record is not valid.
77
97
 */
78
 
static bool get_trace_record(unsigned int idx, TraceRecord *record)
 
98
static bool get_trace_record(unsigned int idx, TraceRecord **recordptr)
79
99
{
80
 
    if (!(trace_buf[idx].event & TRACE_RECORD_VALID)) {
 
100
    uint64_t event_flag = 0;
 
101
    TraceRecord record;
 
102
    /* read the event flag to see if its a valid record */
 
103
    read_from_buffer(idx, &record, sizeof(event_flag));
 
104
 
 
105
    if (!(record.event & TRACE_RECORD_VALID)) {
81
106
        return false;
82
107
    }
83
108
 
84
 
    __sync_synchronize(); /* read memory barrier before accessing record */
85
 
 
86
 
    *record = trace_buf[idx];
87
 
    record->event &= ~TRACE_RECORD_VALID;
 
109
    smp_rmb(); /* read memory barrier before accessing record */
 
110
    /* read the record header to know record length */
 
111
    read_from_buffer(idx, &record, sizeof(TraceRecord));
 
112
    *recordptr = malloc(record.length); /* dont use g_malloc, can deadlock when traced */
 
113
    /* make a copy of record to avoid being overwritten */
 
114
    read_from_buffer(idx, *recordptr, record.length);
 
115
    smp_rmb(); /* memory barrier before clearing valid flag */
 
116
    (*recordptr)->event &= ~TRACE_RECORD_VALID;
 
117
    /* clear the trace buffer range for consumed record otherwise any byte
 
118
     * with its MSB set may be considered as a valid event id when the writer
 
119
     * thread crosses this range of buffer again.
 
120
     */
 
121
    clear_buffer_range(idx, record.length);
88
122
    return true;
89
123
}
90
124
 
120
154
 
121
155
static gpointer writeout_thread(gpointer opaque)
122
156
{
123
 
    TraceRecord record;
124
 
    unsigned int writeout_idx = 0;
125
 
    unsigned int num_available, idx;
 
157
    TraceRecord *recordptr;
 
158
    union {
 
159
        TraceRecord rec;
 
160
        uint8_t bytes[sizeof(TraceRecord) + sizeof(uint64_t)];
 
161
    } dropped;
 
162
    unsigned int idx = 0;
 
163
    uint64_t dropped_count;
126
164
    size_t unused __attribute__ ((unused));
127
165
 
128
166
    for (;;) {
129
167
        wait_for_trace_records_available();
130
168
 
131
 
        num_available = trace_idx - writeout_idx;
132
 
        if (num_available > TRACE_BUF_LEN) {
133
 
            record = (TraceRecord){
134
 
                .event = DROPPED_EVENT_ID,
135
 
                .x1 = num_available,
136
 
            };
137
 
            unused = fwrite(&record, sizeof(record), 1, trace_fp);
138
 
            writeout_idx += num_available;
 
169
        if (dropped_events) {
 
170
            dropped.rec.event = DROPPED_EVENT_ID,
 
171
            dropped.rec.timestamp_ns = get_clock();
 
172
            dropped.rec.length = sizeof(TraceRecord) + sizeof(dropped_events),
 
173
            dropped.rec.reserved = 0;
 
174
            while (1) {
 
175
                dropped_count = dropped_events;
 
176
                if (g_atomic_int_compare_and_exchange((gint *)&dropped_events,
 
177
                                                      dropped_count, 0)) {
 
178
                    break;
 
179
                }
 
180
            }
 
181
            memcpy(dropped.rec.arguments, &dropped_count, sizeof(uint64_t));
 
182
            unused = fwrite(&dropped.rec, dropped.rec.length, 1, trace_fp);
139
183
        }
140
184
 
141
 
        idx = writeout_idx % TRACE_BUF_LEN;
142
 
        while (get_trace_record(idx, &record)) {
143
 
            trace_buf[idx].event = 0; /* clear valid bit */
144
 
            unused = fwrite(&record, sizeof(record), 1, trace_fp);
145
 
            idx = ++writeout_idx % TRACE_BUF_LEN;
 
185
        while (get_trace_record(idx, &recordptr)) {
 
186
            unused = fwrite(recordptr, recordptr->length, 1, trace_fp);
 
187
            writeout_idx += recordptr->length;
 
188
            free(recordptr); /* dont use g_free, can deadlock when traced */
 
189
            idx = writeout_idx % TRACE_BUF_LEN;
146
190
        }
147
191
 
148
192
        fflush(trace_fp);
150
194
    return NULL;
151
195
}
152
196
 
153
 
static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
154
 
                  uint64_t x4, uint64_t x5, uint64_t x6)
155
 
{
156
 
    unsigned int idx;
157
 
    uint64_t timestamp;
158
 
 
159
 
    if (!trace_list[event].state) {
160
 
        return;
161
 
    }
162
 
 
163
 
    timestamp = get_clock();
164
 
 
165
 
    idx = g_atomic_int_exchange_and_add((gint *)&trace_idx, 1) % TRACE_BUF_LEN;
166
 
    trace_buf[idx] = (TraceRecord){
167
 
        .event = event,
168
 
        .timestamp_ns = timestamp,
169
 
        .x1 = x1,
170
 
        .x2 = x2,
171
 
        .x3 = x3,
172
 
        .x4 = x4,
173
 
        .x5 = x5,
174
 
        .x6 = x6,
175
 
    };
176
 
    __sync_synchronize(); /* write barrier before marking as valid */
177
 
    trace_buf[idx].event |= TRACE_RECORD_VALID;
178
 
 
179
 
    if ((idx + 1) % TRACE_BUF_FLUSH_THRESHOLD == 0) {
 
197
void trace_record_write_u64(TraceBufferRecord *rec, uint64_t val)
 
198
{
 
199
    rec->rec_off = write_to_buffer(rec->rec_off, &val, sizeof(uint64_t));
 
200
}
 
201
 
 
202
void trace_record_write_str(TraceBufferRecord *rec, const char *s, uint32_t slen)
 
203
{
 
204
    /* Write string length first */
 
205
    rec->rec_off = write_to_buffer(rec->rec_off, &slen, sizeof(slen));
 
206
    /* Write actual string now */
 
207
    rec->rec_off = write_to_buffer(rec->rec_off, (void*)s, slen);
 
208
}
 
209
 
 
210
int trace_record_start(TraceBufferRecord *rec, TraceEventID event, size_t datasize)
 
211
{
 
212
    unsigned int idx, rec_off, old_idx, new_idx;
 
213
    uint32_t rec_len = sizeof(TraceRecord) + datasize;
 
214
    uint64_t timestamp_ns = get_clock();
 
215
 
 
216
    while (1) {
 
217
        old_idx = trace_idx;
 
218
        smp_rmb();
 
219
        new_idx = old_idx + rec_len;
 
220
 
 
221
        if (new_idx - writeout_idx > TRACE_BUF_LEN) {
 
222
            /* Trace Buffer Full, Event dropped ! */
 
223
            g_atomic_int_inc((gint *)&dropped_events);
 
224
            return -ENOSPC;
 
225
        }
 
226
 
 
227
        if (g_atomic_int_compare_and_exchange((gint *)&trace_idx,
 
228
                                              old_idx, new_idx)) {
 
229
            break;
 
230
        }
 
231
    }
 
232
 
 
233
    idx = old_idx % TRACE_BUF_LEN;
 
234
    /*  To check later if threshold crossed */
 
235
    rec->next_tbuf_idx = new_idx % TRACE_BUF_LEN;
 
236
 
 
237
    rec_off = idx;
 
238
    rec_off = write_to_buffer(rec_off, (uint8_t*)&event, sizeof(event));
 
239
    rec_off = write_to_buffer(rec_off, (uint8_t*)&timestamp_ns, sizeof(timestamp_ns));
 
240
    rec_off = write_to_buffer(rec_off, (uint8_t*)&rec_len, sizeof(rec_len));
 
241
 
 
242
    rec->tbuf_idx = idx;
 
243
    rec->rec_off  = (idx + sizeof(TraceRecord)) % TRACE_BUF_LEN;
 
244
    return 0;
 
245
}
 
246
 
 
247
static void read_from_buffer(unsigned int idx, void *dataptr, size_t size)
 
248
{
 
249
    uint8_t *data_ptr = dataptr;
 
250
    uint32_t x = 0;
 
251
    while (x < size) {
 
252
        if (idx >= TRACE_BUF_LEN) {
 
253
            idx = idx % TRACE_BUF_LEN;
 
254
        }
 
255
        data_ptr[x++] = trace_buf[idx++];
 
256
    }
 
257
}
 
258
 
 
259
static unsigned int write_to_buffer(unsigned int idx, void *dataptr, size_t size)
 
260
{
 
261
    uint8_t *data_ptr = dataptr;
 
262
    uint32_t x = 0;
 
263
    while (x < size) {
 
264
        if (idx >= TRACE_BUF_LEN) {
 
265
            idx = idx % TRACE_BUF_LEN;
 
266
        }
 
267
        trace_buf[idx++] = data_ptr[x++];
 
268
    }
 
269
    return idx; /* most callers wants to know where to write next */
 
270
}
 
271
 
 
272
void trace_record_finish(TraceBufferRecord *rec)
 
273
{
 
274
    uint8_t temp_rec[sizeof(TraceRecord)];
 
275
    TraceRecord *record = (TraceRecord *) temp_rec;
 
276
    read_from_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
 
277
    smp_wmb(); /* write barrier before marking as valid */
 
278
    record->event |= TRACE_RECORD_VALID;
 
279
    write_to_buffer(rec->tbuf_idx, temp_rec, sizeof(TraceRecord));
 
280
 
 
281
    if ((trace_idx - writeout_idx) > TRACE_BUF_FLUSH_THRESHOLD) {
180
282
        flush_trace_file(false);
181
283
    }
182
284
}
183
285
 
184
 
void trace0(TraceEventID event)
185
 
{
186
 
    trace(event, 0, 0, 0, 0, 0, 0);
187
 
}
188
 
 
189
 
void trace1(TraceEventID event, uint64_t x1)
190
 
{
191
 
    trace(event, x1, 0, 0, 0, 0, 0);
192
 
}
193
 
 
194
 
void trace2(TraceEventID event, uint64_t x1, uint64_t x2)
195
 
{
196
 
    trace(event, x1, x2, 0, 0, 0, 0);
197
 
}
198
 
 
199
 
void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3)
200
 
{
201
 
    trace(event, x1, x2, x3, 0, 0, 0);
202
 
}
203
 
 
204
 
void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4)
205
 
{
206
 
    trace(event, x1, x2, x3, x4, 0, 0);
207
 
}
208
 
 
209
 
void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5)
210
 
{
211
 
    trace(event, x1, x2, x3, x4, x5, 0);
212
 
}
213
 
 
214
 
void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6)
215
 
{
216
 
    trace(event, x1, x2, x3, x4, x5, x6);
217
 
}
218
 
 
219
286
void st_set_trace_file_enabled(bool enable)
220
287
{
221
288
    if (enable == !!trace_fp) {
228
295
    flush_trace_file(true);
229
296
 
230
297
    if (enable) {
231
 
        static const TraceRecord header = {
232
 
            .event = HEADER_EVENT_ID,
233
 
            .timestamp_ns = HEADER_MAGIC,
234
 
            .x1 = HEADER_VERSION,
 
298
        static const TraceRecordHeader header = {
 
299
            .header_event_id = HEADER_EVENT_ID,
 
300
            .header_magic = HEADER_MAGIC,
 
301
            /* Older log readers will check for version at next location */
 
302
            .header_version = HEADER_VERSION,
235
303
        };
236
304
 
237
305
        trace_fp = fopen(trace_file_name, "wb");
288
356
                  trace_file_name, trace_fp ? "on" : "off");
289
357
}
290
358
 
291
 
void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
292
 
{
293
 
    unsigned int i;
294
 
 
295
 
    for (i = 0; i < TRACE_BUF_LEN; i++) {
296
 
        TraceRecord record;
297
 
 
298
 
        if (!get_trace_record(i, &record)) {
299
 
            continue;
300
 
        }
301
 
        stream_printf(stream, "Event %" PRIu64 " : %" PRIx64 " %" PRIx64
302
 
                      " %" PRIx64 " %" PRIx64 " %" PRIx64 " %" PRIx64 "\n",
303
 
                      record.event, record.x1, record.x2,
304
 
                      record.x3, record.x4, record.x5,
305
 
                      record.x6);
306
 
    }
307
 
}
308
 
 
309
359
void st_flush_trace_buffer(void)
310
360
{
311
361
    flush_trace_file(true);
363
413
    sigfillset(&set);
364
414
    pthread_sigmask(SIG_SETMASK, &set, &oldset);
365
415
#endif
366
 
    thread = g_thread_create(writeout_thread, NULL, FALSE, NULL);
 
416
    thread = g_thread_create(fn, NULL, FALSE, NULL);
367
417
#ifndef _WIN32
368
418
    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
369
419
#endif