Currently simpletrace assumes that events are given IDs starting from 0, based on the order in which they appear in the trace-events file, with no gaps. When the trace-events file is split up, this assumption becomes problematic. To deal with this, extend the simpletrace format so that it outputs a table of event name <-> ID mappings. That will allow QEMU to assign arbitrary IDs to events without breaking simpletrace parsing. The v3 simple trace format was FILE HEADER EVENT TRACE RECORD 0 EVENT TRACE RECORD 1 ... EVENT TRACE RECORD N The v4 simple trace format is now FILE HEADER EVENT MAPPING RECORD 0 EVENT MAPPING RECORD 1 ... EVENT MAPPING RECORD M EVENT TRACE RECORD RECORD 0 EVENT TRACE RECORD RECORD 1 ... EVENT TRACE RECORD N Although this shows all the mapping records being emitted upfront, this is not required by the format. While the main simpletrace backend will emit all mappings at startup, the systemtap simpletrace.stp script will emit the mappings at first use. eg FILE HEADER ... EVENT MAPPING RECORD 0 EVENT TRACE RECORD RECORD 0 EVENT TRACE RECORD RECORD 1 EVENT MAPPING RECORD 1 EVENT TRACE RECORD RECORD 2 ... EVENT TRACE RECORD N This is more space efficient given that most trace records only include a subset of events. In modifying the systemtap simpletrace code, a 'begin' probe was added to emit the trace event header, so you no longer need to add '--no-header' when running simpletrace.py for systemtap generated trace files. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> Message-id: 1475588159-30598-12-git-send-email-berrange@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
92 lines
3.1 KiB
Python
92 lines
3.1 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Generate .stp file that outputs simpletrace binary traces (DTrace with SystemTAP only).
|
|
"""
|
|
|
|
__author__ = "Stefan Hajnoczi <redhat.com>"
|
|
__copyright__ = "Copyright (C) 2014, Red Hat, Inc."
|
|
__license__ = "GPL version 2 or (at your option) any later version"
|
|
|
|
__maintainer__ = "Stefan Hajnoczi"
|
|
__email__ = "stefanha@redhat.com"
|
|
|
|
|
|
from tracetool import out
|
|
from tracetool.backend.dtrace import binary, probeprefix
|
|
from tracetool.backend.simple import is_string
|
|
from tracetool.format.stap import stap_escape
|
|
|
|
|
|
def generate(events, backend):
|
|
out('/* This file is autogenerated by tracetool, do not edit. */',
|
|
'',
|
|
'global event_name_to_id_map',
|
|
'global event_next_id',
|
|
'function simple_trace_map_event(name)',
|
|
'',
|
|
'{',
|
|
' if (!([name] in event_name_to_id_map)) {',
|
|
' event_name_to_id_map[name] = event_next_id',
|
|
' name_len = strlen(name)',
|
|
' printf("%%8b%%8b%%4b%%.*s", 0, ',
|
|
' event_next_id, name_len, name_len, name)',
|
|
' event_next_id = event_next_id + 1',
|
|
' }',
|
|
' return event_name_to_id_map[name]',
|
|
'}',
|
|
'probe begin',
|
|
'{',
|
|
' printf("%%8b%%8b%%8b", 0xffffffffffffffff, 0xf2b177cb0aa429b4, 4)',
|
|
'}',
|
|
'')
|
|
|
|
for event_id, e in enumerate(events):
|
|
if 'disable' in e.properties:
|
|
continue
|
|
|
|
out('probe %(probeprefix)s.simpletrace.%(name)s = %(probeprefix)s.%(name)s ?',
|
|
'{',
|
|
' id = simple_trace_map_event("%(name)s")',
|
|
probeprefix=probeprefix(),
|
|
name=e.name)
|
|
|
|
# Calculate record size
|
|
sizes = ['24'] # sizeof(TraceRecord)
|
|
for type_, name in e.args:
|
|
name = stap_escape(name)
|
|
if is_string(type_):
|
|
out(' try {',
|
|
' arg%(name)s_str = %(name)s ? user_string_n(%(name)s, 512) : "<null>"',
|
|
' } catch {}',
|
|
' arg%(name)s_len = strlen(arg%(name)s_str)',
|
|
name=name)
|
|
sizes.append('4 + arg%s_len' % name)
|
|
else:
|
|
sizes.append('8')
|
|
sizestr = ' + '.join(sizes)
|
|
|
|
# Generate format string and value pairs for record header and arguments
|
|
fields = [('8b', 'id'),
|
|
('8b', 'gettimeofday_ns()'),
|
|
('4b', sizestr),
|
|
('4b', 'pid()')]
|
|
for type_, name in e.args:
|
|
name = stap_escape(name)
|
|
if is_string(type_):
|
|
fields.extend([('4b', 'arg%s_len' % name),
|
|
('.*s', 'arg%s_len, arg%s_str' % (name, name))])
|
|
else:
|
|
fields.append(('8b', name))
|
|
|
|
# Emit the entire record in a single SystemTap printf()
|
|
fmt_str = '%'.join(fmt for fmt, _ in fields)
|
|
arg_str = ', '.join(arg for _, arg in fields)
|
|
out(' printf("%%8b%%%(fmt_str)s", 1, %(arg_str)s)',
|
|
fmt_str=fmt_str, arg_str=arg_str)
|
|
|
|
out('}')
|
|
|
|
out()
|