All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] trace-cruncher: Add khist class to ft_utiles
@ 2022-01-06 13:21 Yordan Karadzhov (VMware)
  2022-01-06 13:21 ` [PATCH 2/3] trace-cruncher: Add example for the high-level histogram APIs Yordan Karadzhov (VMware)
  2022-01-06 13:21 ` [PATCH 3/3] trace-cruncher: Add tests for the khist class Yordan Karadzhov (VMware)
  0 siblings, 2 replies; 3+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-06 13:21 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Define a Python class to be used for easy manipulation of kernel
histograms.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 tracecruncher/ft_utils.py | 124 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/tracecruncher/ft_utils.py b/tracecruncher/ft_utils.py
index cae54b0..ed4bdcd 100644
--- a/tracecruncher/ft_utils.py
+++ b/tracecruncher/ft_utils.py
@@ -210,3 +210,127 @@ class kretval_probe(kprobe_base):
         """
         self.kp = ft.register_kprobe(event=self.name, function=self.func);
         self.evt_id = find_event_id(system=ft.tc_event_system(), event=self.name)
+
+
+class khist:
+    def __init__(self, name, event, axes, weights=[],
+                 sort_keys=[], sort_dir={}, find=False):
+        """ Constructor.
+        """
+        self.name = name
+        self.inst = None
+
+        inst_name = name+'_inst'
+        if find:
+            self.inst = ft.find_instance(name=inst_name)
+            self.attached = False
+        else:
+            self.inst = ft.create_instance(name=inst_name)
+            self.attached = True
+
+        self.hist = ft.hist(name=name,
+                            system=event.system,
+                            event=event.name,
+                            axes=axes)
+
+        for v in weights:
+            self.hist.add_value(value=v)
+
+        self.hist.sort_keys(keys=sort_keys)
+
+        for key, val in sort_dir.items():
+            self.hist.sort_key_direction(sort_key=key,
+                                         direction=val)
+
+        self.trigger = '{0}/events/{1}/{2}/trigger'.format(self.inst.dir(),
+                                                           event.system,
+                                                           event.name)
+
+        if not find:
+            # Put the kernel histogram on 'standby'
+            self.hist.stop(self.inst)
+
+    def __del__(self):
+        """ Destructor.
+        """
+        if self.inst and self.attached:
+            self.clear()
+
+    def start(self):
+        """ Start accumulating data.
+        """
+        self.hist.resume(self.inst)
+
+    def stop(self):
+        """ Stop accumulating data.
+        """
+        self.hist.stop(self.inst)
+
+    def resume(self):
+        """ Continue accumulating data.
+        """
+        self.hist.resume(self.inst)
+
+    def data(self):
+        """ Read the accumulated data.
+        """
+        return self.hist.read(self.inst)
+
+    def clear(self):
+        """ Clear the accumulated data.
+        """
+        self.hist.clear(self.inst)
+
+    def detach(self):
+        """ Detach the object from the Python module.
+        """
+        ft.detach(self.inst)
+        self.attached = False
+
+    def attach(self):
+        """ Attach the object to the Python module.
+        """
+        ft.attach(self.inst)
+        self.attached = True
+
+    def is_attached(self):
+        """ Check if the object is attached to the Python module.
+        """
+        return self.attached
+
+    def __repr__(self):
+        """ Read the descriptor of the histogram.
+        """
+        with open(self.trigger) as f:
+            return f.read().rstrip()
+
+    def __str__(self):
+        return self.data()
+
+
+def create_khist(name, event, axes, weights=[],
+                 sort_keys=[], sort_dir={}):
+    """ Create new kernel histogram.
+    """
+    try:
+        hist = khist(name=name, event=event, axes=axes, weights=weights,
+                     sort_keys=sort_keys, sort_dir=sort_dir, find=False)
+    except Exception as err:
+        msg = 'Failed to create histogram \'{0}\''.format(name)
+        raise RuntimeError(msg) from err
+
+    return hist
+
+
+def find_khist(name, event, axes, instance=None,
+               weights=[], sort_keys=[], sort_dir={}):
+    """ Find existing kernel histogram.
+    """
+    try:
+        hist = khist(name=name, event=event, axes=axes, weights=weights,
+                     sort_keys=sort_keys, sort_dir=sort_dir, find=True)
+    except Exception as err:
+        msg = 'Failed to find histogram \'{0}\''.format(name)
+        raise RuntimeError(msg) from err
+
+    return hist
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/3] trace-cruncher: Add example for the high-level histogram APIs
  2022-01-06 13:21 [PATCH 1/3] trace-cruncher: Add khist class to ft_utiles Yordan Karadzhov (VMware)
@ 2022-01-06 13:21 ` Yordan Karadzhov (VMware)
  2022-01-06 13:21 ` [PATCH 3/3] trace-cruncher: Add tests for the khist class Yordan Karadzhov (VMware)
  1 sibling, 0 replies; 3+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-06 13:21 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

This is a very basic example, demonstrating the usage of the new
high-level (OOP) APIs for kernel histograms.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 examples/hist_oop.py | 81 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 examples/hist_oop.py

diff --git a/examples/hist_oop.py b/examples/hist_oop.py
new file mode 100644
index 0000000..1a3aab6
--- /dev/null
+++ b/examples/hist_oop.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+
+"""
+SPDX-License-Identifier: CC-BY-4.0
+
+Copyright 2021 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@gmail.com>
+"""
+
+import sys
+import time
+
+import tracecruncher.ft_utils as tc
+
+name = 'khist_example_oop'
+
+cmds = ['start', 'stop', 'show', 'continue', 'clear', 'close']
+
+evt = tc.event('kmem', 'kmalloc')
+
+axes={'call_site': 'sym',
+      'bytes_req': 'n'}
+
+weights=['bytes_alloc']
+
+sort_keys=['bytes_req', 'bytes_alloc']
+
+sort_dir={'bytes_req': 'desc'}
+
+if __name__ == "__main__":
+    if len(sys.argv) != 2:
+        sys.exit(1)
+
+    if not sys.argv[1].isdigit() and not sys.argv[1] in cmds:
+        sys.exit(1)
+
+    arg1 = sys.argv[1]
+    if arg1.isdigit() or arg1 == 'start':
+        # Create the kernel tracing histogram.
+        hist = tc.create_khist(name=name, event=evt, axes=axes, weights=weights,
+                               sort_keys=sort_keys, sort_dir=sort_dir)
+        # Start taking data.
+        hist.start()
+
+        if arg1.isdigit():
+            # Take data for a while, then stop, print the result and exit. The
+            # trace-cruncher module will take care for clearing and destroying
+            # the histogram in the kernel.
+            time.sleep(int(arg1))
+            hist.stop()
+            print(hist.data())
+
+        else:
+            # Detach the 'hist' object from the trace-cruncher module. This will
+            # prevent the kernel histogram from being destroyed when the module
+            # is closed (at exit).
+            hist.detach()
+
+    else:
+        # Try to find an existing histogram with the same definition.
+        # The returned histogram is detached from the trace-cruncher module.
+        hist = tc.find_khist(name=name, event=evt, axes=axes, weights=weights,
+                             sort_keys=sort_keys, sort_dir=sort_dir)
+
+        if arg1 == 'stop':
+            # Stop taking data.
+            hist.stop()
+        elif arg1 == 'show':
+            # Print the collected data.
+            print(hist.data())
+        elif arg1 == 'continue':
+            # Continue taking data.
+            hist.resume()
+        elif arg1 == 'clear':
+            # Reset the histogram.
+            hist.clear()
+
+        if arg1 == 'close':
+            # Attach the 'hist' object to the trace-cruncher module. This will
+            # ensure that the kernel histogram will be destroyed when the
+            # module is closed (at exit).
+            hist.attach()
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 3/3] trace-cruncher: Add tests for the khist class
  2022-01-06 13:21 [PATCH 1/3] trace-cruncher: Add khist class to ft_utiles Yordan Karadzhov (VMware)
  2022-01-06 13:21 ` [PATCH 2/3] trace-cruncher: Add example for the high-level histogram APIs Yordan Karadzhov (VMware)
@ 2022-01-06 13:21 ` Yordan Karadzhov (VMware)
  1 sibling, 0 replies; 3+ messages in thread
From: Yordan Karadzhov (VMware) @ 2022-01-06 13:21 UTC (permalink / raw)
  To: linux-trace-devel; +Cc: Yordan Karadzhov (VMware)

Testing the high-level Python APIs for kernel histograms.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 .../tests/1_unit/test_01_ftracepy_unit.py     | 91 +++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py b/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
index 7e5b20e..87b2be8 100644
--- a/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
+++ b/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
@@ -10,6 +10,7 @@ import os
 import sys
 import unittest
 import tracecruncher.ftracepy as ft
+import tracecruncher.ft_utils as tc
 
 instance_name = 'test_instance1'
 another_instance_name = 'test_instance2'
@@ -600,5 +601,95 @@ class HistTestCase(unittest.TestCase):
         hist.close(inst)
 
 
+hist_name = 'h2d'
+evt_sys = 'kmem'
+evt_name = 'kmalloc'
+
+axes={'call_site': 'sym',
+      'bytes_req': 'n'}
+weights=['bytes_alloc']
+sort_keys=['bytes_req', 'bytes_alloc']
+sort_dir={'bytes_req': 'desc'}
+
+tgr_file = '{0}/instances/{1}_inst/events/{2}/{3}/trigger'.format(ft.dir(), hist_name, evt_sys, evt_name)
+
+class HistOopTestCase(unittest.TestCase):
+    def test_hist_create(self):
+        evt = tc.event(evt_sys, evt_name)
+        hist = tc.create_khist(name=hist_name, event=evt, axes=axes, weights=weights,
+                               sort_keys=sort_keys, sort_dir=sort_dir)
+        f = open(tgr_file)
+        h_buff = f.read()
+        self.assertTrue('hist:name=h2d' in h_buff)
+        self.assertTrue(':keys=call_site.sym,bytes_req' in h_buff)
+        self.assertTrue(':vals=hitcount,bytes_alloc' in h_buff)
+        self.assertTrue(':sort=bytes_req.descending,bytes_alloc' in str(h_buff))
+
+        f.close()
+
+    def test_hist_ctrl(self):
+        evt = tc.event(evt_sys, evt_name)
+        hist = tc.create_khist(name=hist_name, event=evt, axes=axes, weights=weights,
+                               sort_keys=sort_keys, sort_dir=sort_dir)
+        f = open(tgr_file)
+        h_buff = f.read()
+        self.assertTrue('[paused]' in h_buff)
+
+        hist.start()
+        f.seek(0)
+        h_buff = f.read()
+        self.assertTrue('[active]' in h_buff)
+
+        hist.stop()
+        f.seek(0)
+        h_buff = f.read()
+        self.assertTrue('[paused]' in h_buff)
+
+        hist.resume()
+        f.seek(0)
+        h_buff = f.read()
+        self.assertTrue('[active]' in h_buff)
+
+        h_buff = hist.data()
+        self.assertTrue('Totals:' in h_buff)
+
+        hist.stop()
+        hist.clear()
+        f.seek(0)
+        h_buff = f.read()
+        self.assertTrue('[paused]' in h_buff)
+        h_buff = hist.data()
+        self.assertTrue('Hits: 0' in h_buff)
+        self.assertTrue('Entries: 0' in h_buff)
+        self.assertTrue('Dropped: 0' in h_buff)
+
+        f.close()
+
+    def test_1_detach(self):
+        evt = tc.event(evt_sys, evt_name)
+        hist = tc.create_khist(name=hist_name, event=evt, axes=axes, weights=weights,
+                               sort_keys=sort_keys, sort_dir=sort_dir)
+        self.assertTrue(hist.is_attached())
+        hist.detach()
+        self.assertFalse(hist.is_attached())
+
+    def test_2_attach(self):
+        evt = tc.event(evt_sys, evt_name)
+        hist = tc.find_khist(name=hist_name, event=evt, axes=axes, weights=weights,
+                             sort_keys=sort_keys, sort_dir=sort_dir)
+        self.assertFalse(hist.is_attached())
+        hist.attach()
+        self.assertTrue(hist.is_attached())
+
+    def test_hist_err(self):
+        evt = tc.event(evt_sys, evt_name)
+
+        err = 'Failed to find histogram'
+        with self.assertRaises(Exception) as context:
+            hist = tc.find_khist(name=hist_name, event=evt, axes=axes, weights=weights,
+                                 sort_keys=sort_keys, sort_dir=sort_dir)
+        self.assertTrue(err in str(context.exception))
+
+
 if __name__ == '__main__':
     unittest.main()
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-01-06 13:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-06 13:21 [PATCH 1/3] trace-cruncher: Add khist class to ft_utiles Yordan Karadzhov (VMware)
2022-01-06 13:21 ` [PATCH 2/3] trace-cruncher: Add example for the high-level histogram APIs Yordan Karadzhov (VMware)
2022-01-06 13:21 ` [PATCH 3/3] trace-cruncher: Add tests for the khist class Yordan Karadzhov (VMware)

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.