Closes #66.
Signed-off-by: Martin Milata mmilata@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]