File:  [Qemu by Fabrice Bellard] / qemu / simpletrace.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:34:12 2018 UTC (17 months, 2 weeks ago) by root
Branches: qemu, MAIN
CVS tags: qemu0150, qemu0141, qemu0140, HEAD
qemu 0.14.0

    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