[sheepdog] [PATCH 2/2] lttng: add a script based on babeltrace for analyzing request latency

Hitoshi Mitake mitake.hitoshi at lab.ntt.co.jp
Fri Jan 16 10:30:37 CET 2015


Cc: Gu Ping <guping610 at qq.com>
Signed-off-by: Hitoshi Mitake <mitake.hitoshi at lab.ntt.co.jp>
---
 lttng/request.py | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 180 insertions(+)
 create mode 100755 lttng/request.py

diff --git a/lttng/request.py b/lttng/request.py
new file mode 100755
index 0000000..5c8ecc1
--- /dev/null
+++ b/lttng/request.py
@@ -0,0 +1,180 @@
+#! /usr/bin/env python3.4
+
+# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version
+# 2 as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Based on: http://lttng.org/docs/#doc-viewing-and-analyzing-your-traces
+
+# how to use:
+# request.py <path of directory which contains trace data>
+#
+# example:
+# request.py ~/lttng-traces/sheepdog-rxtx-20150116-151005/ust/uid/0/64-bit/
+
+import sys
+import babeltrace
+from enum import Enum
+import copy
+
+class Phase(Enum):
+    Uninitialized = 0
+    Rx_work = 1
+    Rx_main = 2
+    Tx_work = 3
+    Tx_main = 4
+    Incorrect = 5
+
+nr_completed_reqs = 0
+total_required_time = 0
+worst_latency = -1
+best_latency = sys.maxsize
+
+class Request:
+    def __init__(self, id_ptr):
+        self.id_ptr = id_ptr
+        self.phase = Phase.Uninitialized
+
+        self.events = []
+
+    def is_uninitialized(self):
+        return self.phase == Phase.Uninitialized
+
+    def is_finished(self):
+        return self.phase == Phase.Tx_main
+
+    def transition(self, evt):
+        if self.phase == Phase.Incorrect:
+            # do nothing on incorrect request
+            return
+
+        if self.phase == Phase.Uninitialized:
+            if evt.name != "request:rx_work":
+                self.phase = Phase.Incorrect
+                return
+
+            self.phase = Phase.Rx_work
+            self.rwname = evt.name
+            self.rx_work_timestamp = evt.timestamp
+        
+            return
+
+        if self.phase == Phase.Rx_work:
+            if evt.name != "request:rx_main":
+                self.phase = Phase.Incorrect
+                return
+
+            self.phase = Phase.Rx_main
+
+            return
+
+        if self.phase == Phase.Rx_main:
+            if evt.name != "request:tx_work":
+                self.phase = Phase.Incorrect
+                return
+
+            self.phase = Phase.Tx_work
+
+            return
+
+        if self.phase == Phase.Tx_work:
+            if evt.name != "request:tx_main":
+                self.phase = Phase.Incorrect
+                return
+
+            self.phase = Phase.Tx_main
+
+            global nr_completed_reqs
+            global total_required_time
+            global worst_latency
+            global best_latency
+
+            nr_completed_reqs += 1
+            latency = evt.timestamp - self.rx_work_timestamp
+            total_required_time += latency
+            worst_latency = max(worst_latency, latency)
+            best_latency = min(best_latency, latency)
+
+            return
+            
+clients = {}
+
+class Client:
+    def __init__(self, id_fd):
+        self.id_fd = id_fd
+        self.ongoing_reqs = {}
+
+    def feed_event(self, e):
+        if not e['request'] in self.ongoing_reqs:
+            if e.name != "request:rx_work":
+                return
+            req = Request(e['request'])
+            self.ongoing_reqs[e['request']] = req
+        else:
+            req = self.ongoing_reqs[e['request']]
+
+        req.transition(e)
+
+
+def is_focusing_events(event):
+    if event.name == "request:create_client":
+        return True
+    if event.name == "request:clear_client":
+        return True
+    if event.name == "request:rx_work":
+        return True
+    if event.name == "request:rx_main":
+        return True
+    if event.name == "request:tx_work":
+        return True
+    if event.name == "request:tx_main":
+        return True
+    return False
+
+def req_stat():
+    if len(sys.argv) != 2:
+        msg = 'Usage: python {} TRACEPATH'.format(sys.argv[0])
+        raise ValueError(msg)
+
+    # a trace collection holds one to many traces
+    col = babeltrace.TraceCollection()
+
+    # add the trace provided by the user
+    # (LTTng traces always have the 'ctf' format)
+    if col.add_trace(sys.argv[1], 'ctf') is None:
+        raise RuntimeError('Cannot add trace')
+
+    # iterate events
+    for _event in col.events:
+        event = copy.copy(_event)
+        if not is_focusing_events(event):
+            continue
+
+        if event.name == "request:create_client":
+            client = Client(event['fd'])
+            clients[event['fd']] = client
+            continue
+        if event.name == "request:clear_client":
+            if event['fd'] in clients:
+                clients.pop(event['fd'])
+            continue
+
+        # events of rx/tx
+        if not event['fd'] in clients:
+            continue
+
+        clients[event['fd']].feed_event(event)
+
+    print("stat of request latency from clients (QEMU, tgtd, dog)")
+    print("(correctly parsed request: %d)" % nr_completed_reqs)
+    print("average latency: %s ns" % "{0:,d}".format(int(total_required_time / nr_completed_reqs)))
+    print("worst latency: %s ns" % "{0:,d}".format(worst_latency))
+    print("best latency: %s ns" % "{0:,d}".format(best_latency))
+
+if __name__ == '__main__':
+    req_stat()
-- 
1.9.1




More information about the sheepdog mailing list