Annotation of qemu/simpletrace.c, revision 1.1

1.1     ! root        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 "qemu-timer.h"
        !            16: #include "trace.h"
        !            17: 
        !            18: /** Trace file header event ID */
        !            19: #define HEADER_EVENT_ID (~(uint64_t)0) /* avoids conflicting with TraceEventIDs */
        !            20: 
        !            21: /** Trace file magic number */
        !            22: #define HEADER_MAGIC 0xf2b177cb0aa429b4ULL
        !            23: 
        !            24: /** Trace file version number, bump if format changes */
        !            25: #define HEADER_VERSION 0
        !            26: 
        !            27: /** Trace buffer entry */
        !            28: typedef struct {
        !            29:     uint64_t event;
        !            30:     uint64_t timestamp_ns;
        !            31:     uint64_t x1;
        !            32:     uint64_t x2;
        !            33:     uint64_t x3;
        !            34:     uint64_t x4;
        !            35:     uint64_t x5;
        !            36:     uint64_t x6;
        !            37: } TraceRecord;
        !            38: 
        !            39: enum {
        !            40:     TRACE_BUF_LEN = 64 * 1024 / sizeof(TraceRecord),
        !            41: };
        !            42: 
        !            43: static TraceRecord trace_buf[TRACE_BUF_LEN];
        !            44: static unsigned int trace_idx;
        !            45: static FILE *trace_fp;
        !            46: static char *trace_file_name = NULL;
        !            47: static bool trace_file_enabled = false;
        !            48: 
        !            49: void st_print_trace_file_status(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
        !            50: {
        !            51:     stream_printf(stream, "Trace file \"%s\" %s.\n",
        !            52:                   trace_file_name, trace_file_enabled ? "on" : "off");
        !            53: }
        !            54: 
        !            55: static bool write_header(FILE *fp)
        !            56: {
        !            57:     static const TraceRecord header = {
        !            58:         .event = HEADER_EVENT_ID,
        !            59:         .timestamp_ns = HEADER_MAGIC,
        !            60:         .x1 = HEADER_VERSION,
        !            61:     };
        !            62: 
        !            63:     return fwrite(&header, sizeof header, 1, fp) == 1;
        !            64: }
        !            65: 
        !            66: /**
        !            67:  * set_trace_file : To set the name of a trace file.
        !            68:  * @file : pointer to the name to be set.
        !            69:  *         If NULL, set to the default name-<pid> set at config time.
        !            70:  */
        !            71: bool st_set_trace_file(const char *file)
        !            72: {
        !            73:     st_set_trace_file_enabled(false);
        !            74: 
        !            75:     free(trace_file_name);
        !            76: 
        !            77:     if (!file) {
        !            78:         if (asprintf(&trace_file_name, CONFIG_TRACE_FILE, getpid()) < 0) {
        !            79:             trace_file_name = NULL;
        !            80:             return false;
        !            81:         }
        !            82:     } else {
        !            83:         if (asprintf(&trace_file_name, "%s", file) < 0) {
        !            84:             trace_file_name = NULL;
        !            85:             return false;
        !            86:         }
        !            87:     }
        !            88: 
        !            89:     st_set_trace_file_enabled(true);
        !            90:     return true;
        !            91: }
        !            92: 
        !            93: static void flush_trace_file(void)
        !            94: {
        !            95:     /* If the trace file is not open yet, open it now */
        !            96:     if (!trace_fp) {
        !            97:         trace_fp = fopen(trace_file_name, "w");
        !            98:         if (!trace_fp) {
        !            99:             /* Avoid repeatedly trying to open file on failure */
        !           100:             trace_file_enabled = false;
        !           101:             return;
        !           102:         }
        !           103:         write_header(trace_fp);
        !           104:     }
        !           105: 
        !           106:     if (trace_fp) {
        !           107:         size_t unused; /* for when fwrite(3) is declared warn_unused_result */
        !           108:         unused = fwrite(trace_buf, trace_idx * sizeof(trace_buf[0]), 1, trace_fp);
        !           109:     }
        !           110: }
        !           111: 
        !           112: void st_flush_trace_buffer(void)
        !           113: {
        !           114:     if (trace_file_enabled) {
        !           115:         flush_trace_file();
        !           116:     }
        !           117: 
        !           118:     /* Discard written trace records */
        !           119:     trace_idx = 0;
        !           120: }
        !           121: 
        !           122: void st_set_trace_file_enabled(bool enable)
        !           123: {
        !           124:     if (enable == trace_file_enabled) {
        !           125:         return; /* no change */
        !           126:     }
        !           127: 
        !           128:     /* Flush/discard trace buffer */
        !           129:     st_flush_trace_buffer();
        !           130: 
        !           131:     /* To disable, close trace file */
        !           132:     if (!enable) {
        !           133:         fclose(trace_fp);
        !           134:         trace_fp = NULL;
        !           135:     }
        !           136: 
        !           137:     trace_file_enabled = enable;
        !           138: }
        !           139: 
        !           140: static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3,
        !           141:                   uint64_t x4, uint64_t x5, uint64_t x6)
        !           142: {
        !           143:     TraceRecord *rec = &trace_buf[trace_idx];
        !           144: 
        !           145:     if (!trace_list[event].state) {
        !           146:         return;
        !           147:     }
        !           148: 
        !           149:     rec->event = event;
        !           150:     rec->timestamp_ns = get_clock();
        !           151:     rec->x1 = x1;
        !           152:     rec->x2 = x2;
        !           153:     rec->x3 = x3;
        !           154:     rec->x4 = x4;
        !           155:     rec->x5 = x5;
        !           156:     rec->x6 = x6;
        !           157: 
        !           158:     if (++trace_idx == TRACE_BUF_LEN) {
        !           159:         st_flush_trace_buffer();
        !           160:     }
        !           161: }
        !           162: 
        !           163: void trace0(TraceEventID event)
        !           164: {
        !           165:     trace(event, 0, 0, 0, 0, 0, 0);
        !           166: }
        !           167: 
        !           168: void trace1(TraceEventID event, uint64_t x1)
        !           169: {
        !           170:     trace(event, x1, 0, 0, 0, 0, 0);
        !           171: }
        !           172: 
        !           173: void trace2(TraceEventID event, uint64_t x1, uint64_t x2)
        !           174: {
        !           175:     trace(event, x1, x2, 0, 0, 0, 0);
        !           176: }
        !           177: 
        !           178: void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3)
        !           179: {
        !           180:     trace(event, x1, x2, x3, 0, 0, 0);
        !           181: }
        !           182: 
        !           183: void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4)
        !           184: {
        !           185:     trace(event, x1, x2, x3, x4, 0, 0);
        !           186: }
        !           187: 
        !           188: void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5)
        !           189: {
        !           190:     trace(event, x1, x2, x3, x4, x5, 0);
        !           191: }
        !           192: 
        !           193: void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6)
        !           194: {
        !           195:     trace(event, x1, x2, x3, x4, x5, x6);
        !           196: }
        !           197: 
        !           198: /**
        !           199:  * Flush the trace buffer on exit
        !           200:  */
        !           201: static void __attribute__((constructor)) st_init(void)
        !           202: {
        !           203:     atexit(st_flush_trace_buffer);
        !           204: }
        !           205: 
        !           206: void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
        !           207: {
        !           208:     unsigned int i;
        !           209: 
        !           210:     for (i = 0; i < trace_idx; i++) {
        !           211:         stream_printf(stream, "Event %" PRIu64 " : %" PRIx64 " %" PRIx64
        !           212:                       " %" PRIx64 " %" PRIx64 " %" PRIx64 " %" PRIx64 "\n",
        !           213:                       trace_buf[i].event, trace_buf[i].x1, trace_buf[i].x2,
        !           214:                       trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5,
        !           215:                       trace_buf[i].x6);
        !           216:     }
        !           217: }
        !           218: 
        !           219: void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...))
        !           220: {
        !           221:     unsigned int i;
        !           222: 
        !           223:     for (i = 0; i < NR_TRACE_EVENTS; i++) {
        !           224:         stream_printf(stream, "%s [Event ID %u] : state %u\n",
        !           225:                       trace_list[i].tp_name, i, trace_list[i].state);
        !           226:     }
        !           227: }
        !           228: 
        !           229: static TraceEvent* find_trace_event_by_name(const char *tname)
        !           230: {
        !           231:     unsigned int i;
        !           232: 
        !           233:     if (!tname) {
        !           234:         return NULL;
        !           235:     }
        !           236: 
        !           237:     for (i = 0; i < NR_TRACE_EVENTS; i++) {
        !           238:         if (!strcmp(trace_list[i].tp_name, tname)) {
        !           239:             return &trace_list[i];
        !           240:         }
        !           241:     }
        !           242:     return NULL; /* indicates end of list reached without a match */
        !           243: }
        !           244: 
        !           245: bool st_change_trace_event_state(const char *tname, bool tstate)
        !           246: {
        !           247:     TraceEvent *tp;
        !           248: 
        !           249:     tp = find_trace_event_by_name(tname);
        !           250:     if (tp) {
        !           251:         tp->state = tstate;
        !           252:         return true;
        !           253:     }
        !           254:     return false;
        !           255: }

unix.superglobalmegacorp.com