[SATYR PATCH 9/9] python: bindings for duphash

Martin Milata mmilata at redhat.com
Wed Jun 26 20:14:13 UTC 2013


Closes #66.

Signed-off-by: Martin Milata <mmilata at redhat.com>
---
 python/py_base_thread.c | 39 ++++++++++++++++++++++++++++++++++++++-
 python/py_base_thread.h |  1 +
 python/py_module.c      |  5 +++++
 tests/python/gdb.py     |  5 +++++
 tests/python/java.py    |  9 +++++++++
 tests/python/koops.py   |  5 +++++
 tests/python/python.py  |  9 +++++++++
 7 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/python/py_base_thread.c b/python/py_base_thread.c
index 8053878..5bbbade 100644
--- a/python/py_base_thread.c
+++ b/python/py_base_thread.c
@@ -34,11 +34,19 @@
                      "                      DISTANCE_JACCARD or DISTANCE_DAMERAU_LEVENSHTEIN\n"\
                      "Returns: positive float - distance between the two threads"
 
+#define get_duphash_doc "Usage: thread.get_duphash(frames=0, flags=DUPHASH_NORMAL, prefix='')\n"\
+                        "Returns: string - thread's duplication hash\n"\
+                        "frames: integer - number of frames to use (default 0 means use all)\n"\
+                        "flags: integer - bitwise sum of flags (DUPHASH_NORMAL, DUPHASH_NOHASH,\n"\
+                        "                 DUPHASH_NONORMALIZE)\n"\
+                        "prefix: string - string to be prepended in front of the text before hashing"
+
 static PyMethodDef
 thread_methods[] =
 {
     /* methods */
-    { "distance", (PyCFunction)sr_py_base_thread_distance, METH_VARARGS|METH_KEYWORDS, distance_doc },
+    { "distance",    (PyCFunction)sr_py_base_thread_distance,    METH_VARARGS|METH_KEYWORDS, distance_doc    },
+    { "get_duphash", (PyCFunction)sr_py_base_thread_get_duphash, METH_VARARGS|METH_KEYWORDS, get_duphash_doc },
     { NULL },
 };
 
@@ -242,3 +250,32 @@ sr_py_base_thread_distance(PyObject *self, PyObject *args, PyObject *kwds)
     float dist = sr_distance(dist_type, t1->thread, t2->thread);
     return PyFloat_FromDouble((double)dist);
 }
+
+PyObject *
+sr_py_base_thread_get_duphash(PyObject *self, PyObject *args, PyObject *kwds)
+{
+    const char *prefix = NULL;
+    int frames = 0, flags = 0;
+
+    static const char *kwlist[] = { "frames", "flags", "prefix", NULL };
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iis", (char **)kwlist,
+                                     &frames, &flags, &prefix))
+        return NULL;
+
+    struct sr_py_base_thread *this =
+        (struct sr_py_base_thread *)self;
+    if (frames_prepare_linked_list(this) < 0)
+        return NULL;
+
+    char *hash = sr_thread_get_duphash((struct sr_thread *)this->thread,
+                                       frames, (char *)prefix, flags);
+    if (!hash)
+    {
+        PyErr_SetString(PyExc_RuntimeError, "cannot obtain duphash");
+        return NULL;
+    }
+
+    PyObject *result = PyString_FromString(hash);
+    free(hash);
+    return result;
+}
diff --git a/python/py_base_thread.h b/python/py_base_thread.h
index 663555c..e9f1af7 100644
--- a/python/py_base_thread.h
+++ b/python/py_base_thread.h
@@ -51,6 +51,7 @@ int sr_py_base_thread_cmp(struct sr_py_base_thread *self, struct sr_py_base_thre
 
 /* methods */
 PyObject *sr_py_base_thread_distance(PyObject *self, PyObject *args, PyObject *kwds);
+PyObject *sr_py_base_thread_get_duphash(PyObject *self, PyObject *args, PyObject *kwds);
 
 #ifdef __cplusplus
 }
diff --git a/python/py_module.c b/python/py_module.c
index 36c4e0f..f049a03 100644
--- a/python/py_module.c
+++ b/python/py_module.c
@@ -17,6 +17,7 @@
 #include "py_metrics.h"
 
 #include "distance.h"
+#include "thread.h"
 #include "stacktrace.h"
 #include "gdb/sharedlib.h"
 
@@ -151,6 +152,10 @@ init_satyr()
     PyModule_AddObject(module, "BaseThread",
                        (PyObject *)&sr_py_base_thread_type);
 
+    PyModule_AddIntConstant(module, "DUPHASH_NORMAL", SR_DUPHASH_NORMAL);
+    PyModule_AddIntConstant(module, "DUPHASH_NOHASH", SR_DUPHASH_NOHASH);
+    PyModule_AddIntConstant(module, "DUPHASH_NONORMALIZE", SR_DUPHASH_NONORMALIZE);
+
     Py_INCREF(&sr_py_single_stacktrace_type);
     PyModule_AddObject(module, "SingleThreadStacktrace",
                        (PyObject *)&sr_py_single_stacktrace_type);
diff --git a/tests/python/gdb.py b/tests/python/gdb.py
index 06565b4..2752771 100755
--- a/tests/python/gdb.py
+++ b/tests/python/gdb.py
@@ -78,6 +78,11 @@ class TestGdbThread(BindingsTestCase):
         dup.number = 9000
         self.assertNotEqual(self.thread, dup)
 
+    def test_duphash(self):
+        expected_plain = 'Thread\n  write\n  virNetSocketWriteWire\n  virNetSocketWrite\n'
+        self.assertEqual(self.thread.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain)
+        self.assertEqual(self.thread.get_duphash(), '4ff2e92d89425e18e82b94c214c7ccfec8b31793')
+
 class TestGdbSharedlib(BindingsTestCase):
     def setUp(self):
         self.shlib = satyr.GdbStacktrace(contents).libs[0]
diff --git a/tests/python/java.py b/tests/python/java.py
index dfd5eb0..eaa3d48 100755
--- a/tests/python/java.py
+++ b/tests/python/java.py
@@ -74,6 +74,15 @@ class TestJavaThread(BindingsTestCase):
         dup.name = ' 45678987\n\n\n\n'
         self.assertNotEqual(self.thread, dup)
 
+    def test_duphash(self):
+        expected_plain = '''Thread
+org.hibernate.exception.ConstraintViolationException
+org.hibernate.exception.SQLStateConverter.convert
+org.hibernate.exception.JDBCExceptionHelper.convert
+'''
+        self.assertEqual(self.thread.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain)
+        self.assertEqual(self.thread.get_duphash(), '81450a80a9d9307624b08e80dc244beb63d91138')
+
 class TestJavaSharedlib(BindingsTestCase):
     def setUp(self):
         self.shlib = satyr.JavaStacktrace(contents).libs[0]
diff --git a/tests/python/koops.py b/tests/python/koops.py
index 10cba82..f1de360 100755
--- a/tests/python/koops.py
+++ b/tests/python/koops.py
@@ -70,6 +70,11 @@ class TestKerneloops(BindingsTestCase):
     def test_bthash(self):
         self.assertEqual(self.koops.get_bthash(), '73c7ce83d5ba90a1acbcc7915a62595914321f97')
 
+    def test_duphash(self):
+        expected_plain = 'Thread\n__alloc_pages_nodemask\nip_copy_metadata\nip_forward_options\n'
+        self.assertEqual(self.koops.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain)
+        self.assertEqual(self.koops.get_duphash(), '53f62f9d6f7de093f50653863d200f4789ace7ef')
+
 class TestKoopsFrame(BindingsTestCase):
     def setUp(self):
         self.frame = satyr.Kerneloops(contents).frames[0]
diff --git a/tests/python/python.py b/tests/python/python.py
index 0421935..1fcd49d 100755
--- a/tests/python/python.py
+++ b/tests/python/python.py
@@ -87,6 +87,15 @@ class TestPythonStacktrace(BindingsTestCase):
     def test_bthash(self):
         self.assertEqual(self.trace.get_bthash(), 'fa0a7ff4b65f18661a6ce102eb787ff0d77ff12f')
 
+    def test_duphash(self):
+        expected_plain = '''Thread
+/usr/share/PackageKit/helpers/yum/yumBackend.py:2534
+/usr/share/PackageKit/helpers/yum/yumBackend.py:2593
+/usr/share/PackageKit/helpers/yum/yumBackend.py:2551
+'''
+        self.assertEqual(self.trace.get_duphash(flags=satyr.DUPHASH_NOHASH, frames=3), expected_plain)
+        self.assertEqual(self.trace.get_duphash(), '2c8e509a33966a08df1dd8b2348e850d1bc5b776')
+
 class TestPythonFrame(BindingsTestCase):
     def setUp(self):
         self.frame = satyr.PythonStacktrace(contents).frames[-1]
-- 
1.7.11.7



More information about the Crash-catcher mailing list