From: Koki Sanagi <sanagi.koki@jp.fujitsu.com>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, kaneshige.kenji@jp.fujitsu.com,
izumi.taku@jp.fujitsu.com
Subject: [RFC PATCH 5/5] perf:add a script shows a process of packet
Date: Tue, 08 Jun 2010 14:31:46 +0900 [thread overview]
Message-ID: <4C0DD5C2.4080809@jp.fujitsu.com> (raw)
In-Reply-To: <4C0DD43F.9090902@jp.fujitsu.com>
This perf script show a time-chart of process of packet.
If you want to use it, install perf and
#perf trace record netdev-times
And if you want a result,
#perf trace report netdev-times
Signed-off-by: Koki Sanagi <sanagi.koki@jp.fujitsu.com>
---
tools/perf/scripts/python/bin/netdev-times-record | 7 +
tools/perf/scripts/python/bin/netdev-times-report | 10 +
tools/perf/scripts/python/netdev-times.py | 451 +++++++++++++++++++++
3 files changed, 468 insertions(+), 0 deletions(-)
diff --git a/tools/perf/scripts/python/bin/netdev-times-record b/tools/perf/scripts/python/bin/netdev-times-record
new file mode 100644
index 0000000..c6a54fd
--- /dev/null
+++ b/tools/perf/scripts/python/bin/netdev-times-record
@@ -0,0 +1,7 @@
+#!/bin/bash
+perf record -c 1 -f -R -a -e net:net_dev_xmit -e net:net_dev_queue \
+ -e net:net_dev_receive -e skb:consume_skb \
+ -e skb:dev_kfree_skb_irq -e napi:napi_poll \
+ -e irq:irq_handler_entry -e irq:irq_handler_exit \
+ -e irq:softirq_entry -e irq:softirq_exit \
+ -e irq:softirq_raise -e skb:skb_copy_datagram_iovec
diff --git a/tools/perf/scripts/python/bin/netdev-times-report b/tools/perf/scripts/python/bin/netdev-times-report
new file mode 100644
index 0000000..5d24c3d
--- /dev/null
+++ b/tools/perf/scripts/python/bin/netdev-times-report
@@ -0,0 +1,10 @@
+#!/bin/bash
+# description: displayi a process of packet and processing time
+# args: [comm]
+if [ $# -gt 0 ] ; then
+ if ! expr match "$1" "-" > /dev/null ; then
+ comm=$1
+ shift
+ fi
+fi
+perf trace $@ -s ~/libexec/perf-core/scripts/python/netdev-times.py $comm
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py
new file mode 100644
index 0000000..e7b47c7
--- /dev/null
+++ b/tools/perf/scripts/python/netdev-times.py
@@ -0,0 +1,451 @@
+# Display process of packets and processed time.
+# It helps you to investigate networking.
+
+import os
+import sys
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+ '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
+
+from perf_trace_context import *
+from Core import *
+from Util import *
+
+all_event_list = []; # insert all tracepoint event related with this script
+irq_dic = {}; # key is cpu and value is a list which stacks irqs
+ # which raise NET_RX softirq
+net_rx_dic = {}; # key is cpu and value include time of NET_RX softirq-entry
+ # and a list which stacks receive
+receive_hunk_list = []; # a list which include a sequence of receive events
+receive_skb_list = []; # received packet list for matching
+ # skb_copy_datagram_iovec
+
+queue_list = []; # list of packets which pass through dev_queue_xmit
+xmit_list = []; # list of packets which pass through dev_hard_start_xmit
+free_list = []; # list of packets which is freed
+# Calculate a time interval(msec) from src(nsec) to dst(nsec)
+def diff_msec(src, dst):
+ return (dst - src) / 1000000.0
+
+# Display a process of transmitting a packet
+def print_transmit(hunk):
+ print "%7s %5d %6d.%09dsec %12.6fmsec %12.6fmsec" % \
+ (hunk['dev'], hunk['len'],
+ nsecs_secs(hunk['queue_t']),
+ nsecs_nsecs(hunk['queue_t']),
+ diff_msec(hunk['queue_t'], hunk['xmit_t']),
+ diff_msec(hunk['xmit_t'], hunk['free_t']))
+
+# Display a process of received packets and interrputs associated with
+# a NET_RX softirq
+def print_receive(hunk):
+ if 'irq_list' not in hunk.keys() \
+ or len(hunk['irq_list']) == 0:
+ return
+ irq_list = hunk['irq_list']
+ cpu = irq_list[0]['cpu']
+ base_t = irq_list[0]['irq_ent_t']
+ print "%d.%09dsec cpu=%d" % \
+ (nsecs_secs(base_t), nsecs_nsecs(base_t), cpu)
+ for i in range(len(irq_list)):
+ print "irq_entry(+%fmsec,irq=%d:%s)" % \
+ (diff_msec(base_t, irq_list[i]['irq_ent_t']),
+ irq_list[i]['irq'], irq_list[i]['name'])
+
+ print " |------------" \
+ "softirq_raise(+%fmsec)" % \
+ diff_msec(base_t, irq_list[i]['sirq_raise_t'])
+
+ print "irq_exit (+%fmsec) |" % \
+ diff_msec(base_t, irq_list[i]['irq_ext_t'])
+
+ print " |"
+
+ if 'sirq_ent_t' not in hunk.keys():
+ print 'maybe softirq_entry is dropped'
+ return
+ print " " \
+ "softirq_entry(+%fmsec)\n" \
+ " " \
+ " |" % \
+ diff_msec(base_t, hunk['sirq_ent_t'])
+ event_list = hunk['event_list']
+ for i in range(len(event_list)):
+ event = event_list[i]
+ if event['event_name'] == 'napi_poll':
+ print " " \
+ "napi_poll_exit(+%fmsec, %s)" % \
+ (diff_msec(base_t, event['event_t']), event['dev'])
+ print " " \
+ " |"
+ elif 'comm' in event.keys():
+ print " " \
+ " |---netif_receive_skb" \
+ "(+%fmsec,len=%d)\n" \
+ " " \
+ " | |\n" \
+ " " \
+ " | skb_copy_datagram_iovec" \
+ "(+%fmsec, %d:%s)\n" \
+ " " \
+ " |" % \
+ (diff_msec(base_t, event['event_t']),
+ event['len'],
+ diff_msec(base_t, event['comm_t']),
+ event['pid'], event['comm'])
+ else:
+ print " " \
+ " |---netif_receive_skb" \
+ "(+%fmsec,len=%d)\n" \
+ " " \
+ " |" % \
+ (diff_msec(base_t, event['event_t']),
+ event['len'])
+
+ print " " \
+ "softirq_exit(+%fmsec)\n" % \
+ diff_msec(base_t, hunk['sirq_ext_t'])
+
+def trace_end():
+ # order all events in time
+ all_event_list.sort(lambda a,b :cmp(a['time'], b['time']))
+ # process all events
+ for i in range(len(all_event_list)):
+ event = all_event_list[i]
+ event_name = event['event_name']
+ if event_name == 'irq__softirq_exit':
+ handle_irq_softirq_exit(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['vec'])
+ elif event_name == 'irq__softirq_entry':
+ handle_irq_softirq_entry(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'],event['vec'])
+ elif event_name == 'irq__softirq_raise':
+ handle_irq_softirq_raise(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['vec'])
+ elif event_name == 'irq__irq_handler_entry':
+ handle_irq_handler_entry(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['irq'], event['name'])
+ elif event_name == 'irq__irq_handler_exit':
+ handle_irq_handler_exit(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['irq'], event['ret'])
+ elif event_name == 'napi__napi_poll':
+ handle_napi_poll(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['napi'],
+ event['dev_name'])
+ elif event_name == 'net__net_dev_receive':
+ handle_net_dev_receive(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['skbaddr'],
+ event['skblen'], event['name'])
+ elif event_name == 'skb__skb_copy_datagram_iovec':
+ handle_skb_copy_datagram_iovec(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['skbaddr'],
+ event['skblen'])
+ elif event_name == 'net__net_dev_queue':
+ handle_net_dev_queue(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['skbaddr'],
+ event['skblen'], event['name'])
+ elif event_name == 'net__net_dev_xmit':
+ handle_net_dev_xmit(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['skbaddr'],
+ event['skblen'], event['rc'], event['name'])
+ elif event_name == 'skb__dev_kfree_skb_irq':
+ handle_dev_kfree_skb_irq(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['skbaddr'])
+ elif event_name == 'skb__consume_skb':
+ handle_consume_skb(event['event_name'],
+ event['context'], event['common_cpu'],
+ event['common_pid'], event['common_comm'],
+ event['time'], event['skbaddr'])
+ # display receive hunks
+ for i in range(len(receive_hunk_list)):
+ print_receive(receive_hunk_list[i])
+ # display transmit hunks
+ print " dev len dev_queue_xmit|----------|" \
+ "dev_hard_start_xmit|-----|free_skb"
+ print " | |" \
+ " |"
+ for i in range(len(free_list)):
+ print_transmit(free_list[i])
+
+def irq__softirq_exit(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ vec):
+ if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
+ return
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'vec':vec}
+ all_event_list.append(event_data)
+
+def handle_irq_softirq_exit(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ vec):
+ rec_data = {'sirq_ext_t':time}
+ if common_cpu in irq_dic.keys():
+ rec_data.update({'irq_list':irq_dic[common_cpu]})
+ del irq_dic[common_cpu]
+ if common_cpu in net_rx_dic.keys():
+ rec_data.update({
+ 'event_list':net_rx_dic[common_cpu]['event_list'],
+ 'sirq_ent_t':net_rx_dic[common_cpu]['sirq_ent_t']})
+ del net_rx_dic[common_cpu]
+ # merge information realted to a NET_RX softirq
+ receive_hunk_list.append(rec_data)
+
+def irq__softirq_entry(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ vec):
+ if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
+ return
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'vec':vec}
+ all_event_list.append(event_data)
+
+def handle_irq_softirq_entry(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ vec):
+ net_rx_dic[common_cpu] = {'event_list':[],
+ 'sirq_ent_t':time}
+
+def irq__softirq_raise(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ vec):
+ if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
+ return
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'vec':vec}
+ all_event_list.append(event_data)
+
+def handle_irq_softirq_raise(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ vec):
+ if common_cpu not in irq_dic.keys() \
+ or len(irq_dic[common_cpu]) == 0:
+ return
+ irq = irq_dic[common_cpu].pop()
+ # put a time to prev irq on the same cpu
+ irq.update({'sirq_raise_t':time})
+ irq_dic[common_cpu].append(irq)
+
+def irq__irq_handler_entry(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ irq, name):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'irq':irq, 'name':name}
+ all_event_list.append(event_data)
+
+def handle_irq_handler_entry(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ irq, name):
+ if common_cpu not in irq_dic.keys():
+ irq_dic[common_cpu] = []
+ irq_record = {'irq':irq,
+ 'name':name,
+ 'cpu':common_cpu,
+ 'irq_ent_t':time}
+ irq_dic[common_cpu].append(irq_record)
+
+def irq__irq_handler_exit(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ irq, ret):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'irq':irq, 'ret':ret}
+ all_event_list.append(event_data)
+
+def handle_irq_handler_exit(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ irq, ret):
+ if common_cpu not in irq_dic.keys():
+ return
+ irq_record = irq_dic[common_cpu].pop()
+ irq_record.update({'irq_ext_t':time})
+ # if an irq doesn't include NET_RX softirq, drop.
+ if 'sirq_raise_t' in irq_record.keys():
+ irq_dic[common_cpu].append(irq_record)
+
+def napi__napi_poll(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ napi, dev_name):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'napi':napi, 'dev_name':dev_name}
+ all_event_list.append(event_data)
+
+def handle_napi_poll(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ napi, dev_name):
+ if common_cpu in net_rx_dic.keys():
+ event_list = net_rx_dic[common_cpu]['event_list']
+ rec_data = {'event_name':'napi_poll',
+ 'dev':dev_name,
+ 'event_t':time}
+ event_list.append(rec_data)
+
+def net__net_dev_receive(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ skbaddr,skblen, name):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'skbaddr':skbaddr, 'skblen':skblen, 'name':name}
+ all_event_list.append(event_data)
+
+def handle_net_dev_receive(event_name, context, common_cpu,
+ ccommon_pid, common_comm, time,
+ skbaddr, skblen, name):
+ if common_cpu in net_rx_dic.keys():
+ rec_data = {'event_name':'netif_receive_skb',
+ 'event_t':time,
+ 'skbaddr':skbaddr,
+ 'len':skblen}
+ event_list = net_rx_dic[common_cpu]['event_list']
+ event_list.append(rec_data)
+ receive_skb_list.insert(0, rec_data)
+
+def skb__skb_copy_datagram_iovec(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ skbaddr, skblen):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'skbaddr':skbaddr, 'skblen':skblen}
+ all_event_list.append(event_data)
+
+def handle_skb_copy_datagram_iovec(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ skbaddr, skblen):
+ for i in range(len(receive_skb_list)):
+ rec_data = receive_skb_list[i]
+ if skbaddr == rec_data['skbaddr'] and \
+ 'comm' not in rec_data.keys():
+ rec_data.update({'comm':common_comm,
+ 'pid':common_pid,
+ 'comm_t':time})
+ del receive_skb_list[i]
+ break
+
+def net__net_dev_queue(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ skbaddr, skblen, name):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'skbaddr':skbaddr, 'skblen':skblen, 'name':name}
+ all_event_list.append(event_data)
+
+def handle_net_dev_queue(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ skbaddr, skblen, name):
+ skb = {'dev':name,
+ 'skbaddr':skbaddr,
+ 'len':skblen,
+ 'queue_t':time}
+ xmit_list.insert(0, skb)
+
+def net__net_dev_xmit(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ skbaddr, skblen, rc, name):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'skbaddr':skbaddr, 'skblen':skblen, 'rc':rc, 'name':name}
+ all_event_list.append(event_data)
+
+def handle_net_dev_xmit(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ skbaddr, skblen, rc, name):
+ if rc == 0: # NETDEV_TX_OK
+ for i in range(len(xmit_list)):
+ skb = xmit_list[i]
+ if skb['skbaddr'] == skbaddr:
+ skb['xmit_t'] = time
+ queue_list.insert(0, skb)
+ del xmit_list[i]
+ break
+
+def free_skb(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ skbaddr):
+ for i in range(len(queue_list)):
+ skb = queue_list[i]
+ if skb['skbaddr'] ==skbaddr:
+ skb['free_t'] = time
+ free_list.append(skb)
+ del queue_list[i]
+ break
+
+def skb__dev_kfree_skb_irq(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ skbaddr):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'skbaddr':skbaddr}
+ all_event_list.append(event_data)
+
+def handle_dev_kfree_skb_irq(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ skbaddr):
+ free_skb(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ skbaddr)
+
+def skb__consume_skb(event_name, context, common_cpu,
+ common_secs, common_nsecs, common_pid, common_comm,
+ skbaddr):
+ event_data = {'event_name':event_name, 'context':context,
+ 'common_cpu':common_cpu, 'common_pid':common_pid,
+ 'common_comm':common_comm,'time':nsecs(common_secs,
+ common_nsecs),
+ 'skbaddr':skbaddr}
+ all_event_list.append(event_data)
+
+def handle_consume_skb(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ skbaddr):
+ free_skb(event_name, context, common_cpu,
+ common_pid, common_comm, time,
+ skbaddr)
prev parent reply other threads:[~2010-06-08 5:31 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-08 5:25 [RFC PATCH 0/5] netdev: show a process of packets Koki Sanagi
2010-06-08 5:27 ` [RFC PATCH 1/5] irq: add tracepoint to softirq_raise Koki Sanagi
2010-06-08 5:28 ` [RFC PATCH 2/5] napi: convert trace_napi_poll to TRACE_EVENT Koki Sanagi
2010-06-08 5:30 ` [RFC PATCH 3/5] netdev: add tracepoints to netdev layer Koki Sanagi
2010-06-08 5:30 ` [RFC PATCH 4/5] skb: add tracepoints to freeing skb Koki Sanagi
2010-06-08 5:31 ` Koki Sanagi [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4C0DD5C2.4080809@jp.fujitsu.com \
--to=sanagi.koki@jp.fujitsu.com \
--cc=davem@davemloft.net \
--cc=izumi.taku@jp.fujitsu.com \
--cc=kaneshige.kenji@jp.fujitsu.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.