Skip to content
Snippets Groups Projects
Commit 1e53a52f authored by Tomasz Grabiec's avatar Tomasz Grabiec Committed by Pekka Enberg
Browse files

trace: introduce 'trace list --tcpdump'


The --tcpdump switch enables in-line decoding of net_packet* samples
so that packet content is displayed in human-readable form next to
other samples. This allows to corelate packets with other samples
easily.

Signed-off-by: default avatarTomasz Grabiec <tgrabiec@cloudius-systems.com>
Signed-off-by: default avatarPekka Enberg <penberg@cloudius-systems.com>
parent 0f477a6f
No related branches found
No related tags found
No related merge requests found
...@@ -97,20 +97,24 @@ class Trace: ...@@ -97,20 +97,24 @@ class Trace:
def name(self): def name(self):
return self.tp.name return self.tp.name
def format_data(self): @staticmethod
format = self.tp.format def format_data(sample):
format = sample.tp.format
format = format.replace('%p', '0x%016x') format = format.replace('%p', '0x%016x')
data = [get_formatter(fmt)(arg) for fmt, arg in zip(split_format(self.tp.signature), self.data)] data = [get_formatter(fmt)(arg) for fmt, arg in zip(split_format(sample.tp.signature), sample.data)]
return format % tuple(data) return format % tuple(data)
def format(self, bt_formatter=default_backtrace_formatter): def format(self, bt_formatter=default_backtrace_formatter, data_formatter=None):
if not data_formatter:
data_formatter = self.format_data
return '0x%016x %-15s %2d %19s %-20s %s%s' % ( return '0x%016x %-15s %2d %19s %-20s %s%s' % (
self.thread, self.thread,
self.thread_name, self.thread_name,
self.cpu, self.cpu,
format_time(self.time), format_time(self.time),
self.name, self.name,
self.format_data(), data_formatter(self),
bt_formatter(self.backtrace)) bt_formatter(self.backtrace))
def __str__(self): def __str__(self):
......
...@@ -94,12 +94,17 @@ def get_backtrace_formatter(args): ...@@ -94,12 +94,17 @@ def get_backtrace_formatter(args):
symbol_printer(symbol_resolver(args), src_addr_formatter(args))) symbol_printer(symbol_resolver(args), src_addr_formatter(args)))
def list_trace(args): def list_trace(args):
def data_formatter(sample):
if args.tcpdump and is_net_packet_sample(sample):
return format_packet_sample(sample)
return sample.format_data(sample)
backtrace_formatter = get_backtrace_formatter(args) backtrace_formatter = get_backtrace_formatter(args)
time_range = get_time_range(args) time_range = get_time_range(args)
with get_trace_reader(args) as reader: with get_trace_reader(args) as reader:
for t in reader.get_traces(): for t in reader.get_traces():
if t.time in time_range: if t.time in time_range:
print t.format(backtrace_formatter) print t.format(backtrace_formatter, data_formatter=data_formatter)
def add_time_slicing_options(parser): def add_time_slicing_options(parser):
group = parser.add_argument_group('time slicing') group = parser.add_argument_group('time slicing')
...@@ -217,28 +222,54 @@ def extract(args): ...@@ -217,28 +222,54 @@ def extract(args):
def prof_wait(args): def prof_wait(args):
show_profile(args, get_wait_profile) show_profile(args, get_wait_profile)
def pcap_dump(args, target=None):
if not target:
target = sys.stdout
def needs_dpkt():
global dpkt
try: try:
import dpkt import dpkt
except ImportError: except ImportError:
raise Exception("""Cannot import dpkt. If you don't have it installed you can get it from raise Exception("""Cannot import dpkt. If you don't have it installed you can get it from
https://code.google.com/p/dpkt/downloads""") https://code.google.com/p/dpkt/downloads""")
def write_sample_to_pcap(sample, pcap_writer):
ts = sample.time / 1e9
if sample.name == "net_packet_eth":
pcap_writer.writepkt(str(sample.data[1]), ts=ts)
elif sample.name == "net_packet_loopback":
pkt = dpkt.ethernet.Ethernet()
pkt.data = sample.data[0]
pcap_writer.writepkt(pkt, ts=ts)
else:
raise Exception('Unsupported tracepoint: ' + sample.name)
def format_packet_sample(sample):
assert(is_net_packet_sample(sample))
needs_dpkt()
proc = subprocess.Popen(['tcpdump', '-tn', '-r', '-'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pcap = dpkt.pcap.Writer(proc.stdin)
write_sample_to_pcap(sample, pcap)
pcap.close()
assert(proc.stdout.readline() == "reading from file -, link-type EN10MB (Ethernet)\n")
packet_line = proc.stdout.readline().rstrip()
proc.wait()
return packet_line
def is_net_packet_sample(sample):
return sample.name in ["net_packet_eth", "net_packet_loopback"]
def pcap_dump(args, target=None):
needs_dpkt()
if not target:
target = sys.stdout
pcap_file = dpkt.pcap.Writer(target) pcap_file = dpkt.pcap.Writer(target)
try: try:
with get_trace_reader(args) as reader: with get_trace_reader(args) as reader:
for sample in reader.get_traces(): for sample in reader.get_traces():
ts = sample.time / 1e9 if is_net_packet_sample(sample):
if sample.name == "net_packet_eth": write_sample_to_pcap(sample, pcap_file)
pcap_file.writepkt(sample.data[1], ts=ts)
elif sample.name == "net_packet_loopback":
pkt = dpkt.ethernet.Ethernet()
pkt.data = sample.data[1]
pcap_file.writepkt(pkt, ts=ts)
finally: finally:
pcap_file.close() pcap_file.close()
...@@ -418,6 +449,7 @@ if __name__ == "__main__": ...@@ -418,6 +449,7 @@ if __name__ == "__main__":
cmd_list = subparsers.add_parser("list", help="list trace") cmd_list = subparsers.add_parser("list", help="list trace")
add_trace_listing_options(cmd_list) add_trace_listing_options(cmd_list)
cmd_list.add_argument("--tcpdump", action="store_true")
cmd_list.set_defaults(func=list_trace, paginate=True) cmd_list.set_defaults(func=list_trace, paginate=True)
cmd_list_timed = subparsers.add_parser("list-timed", help="list timed traces", description=""" cmd_list_timed = subparsers.add_parser("list-timed", help="list timed traces", description="""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment