/* methods */ PyObject * sr_py_base_thread_distance(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *other; int dist_type = SR_DISTANCE_LEVENSHTEIN; static const char *kwlist[] = { "other", "dist_type", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|i", (char **)kwlist, &sr_py_base_thread_type, &other, &dist_type)) return NULL; struct sr_py_base_thread *t1 = (struct sr_py_base_thread *)self; struct sr_py_base_thread *t2 = (struct sr_py_base_thread *)other; if (frames_prepare_linked_list(t1) < 0) return NULL; if (frames_prepare_linked_list(t2) < 0) return NULL; if (Py_TYPE(self) != Py_TYPE(other)) { PyErr_SetString(PyExc_TypeError, "Both threads must have the same type"); return NULL; } if (dist_type < 0 || dist_type >= SR_DISTANCE_NUM) { PyErr_SetString(PyExc_ValueError, "Invalid distance type"); return NULL; } float dist = sr_distance(dist_type, t1->thread, t2->thread); return PyFloat_FromDouble((double)dist); }
static int core_backtrace_is_duplicate(struct sr_stacktrace *bt1, const char *bt2_text) { struct sr_thread *thread1 = sr_stacktrace_find_crash_thread(bt1); if (thread1 == NULL) { log_notice("New stacktrace has no crash thread, disabling core stacktrace deduplicate"); dup_corebt_fini(); return 0; } int result; char *error_message; struct sr_stacktrace *bt2 = sr_stacktrace_parse(sr_abrt_type_from_type(type), bt2_text, &error_message); if (bt2 == NULL) { log_notice("Failed to parse backtrace, considering it not duplicate: %s", error_message); free(error_message); return 0; } struct sr_thread *thread2 = sr_stacktrace_find_crash_thread(bt2); if (thread2 == NULL) { log_notice("Failed to get crash thread, considering it not duplicate"); result = 0; goto end; } int length2 = sr_thread_frame_count(thread2); if (length2 <= 0) { log_notice("Core backtrace has zero frames, considering it not duplicate"); result = 0; goto end; } float distance = sr_distance(SR_DISTANCE_DAMERAU_LEVENSHTEIN, thread1, thread2); log_info("Distance between backtraces: %f", distance); result = (distance <= BACKTRACE_DUP_THRESHOLD); end: sr_stacktrace_free(bt2); return result; }
struct sr_distances * sr_threads_compare(struct sr_thread **threads, int m, int n, enum sr_distance_type dist_type) { struct sr_distances *distances; int i, j; float dist; distances = sr_distances_new(m, n); if (n <= 0) return distances; /* Check that all threads are of the same type */ enum sr_report_type type, prev_type = threads[0]->type; for (i = 0; i < n; i++) { type = threads[i]->type; assert(prev_type == type); prev_type = type; } for (i = 0; i < m; i++) { for (j = i + 1; j < n; j++) { /* XXX: GDB crashes have a special normalization step for * clustering. If there's something similar for other types, we can * generalize it -- meanwhile there's a separate case for GDB here */ if (type == SR_REPORT_GDB) { struct sr_gdb_thread *thread1 = (struct sr_gdb_thread*)threads[i], *thread2 = (struct sr_gdb_thread*)threads[j]; int ok = 0, all = 0; sr_gdb_thread_quality_counts(thread1, &ok, &all); sr_gdb_thread_quality_counts(thread2, &ok, &all); if (ok != all) { /* There are some unknown function names, try to pair them, but * the threads need to be copied first. */ thread1 = sr_gdb_thread_dup(thread1, false); thread2 = sr_gdb_thread_dup(thread2, false); sr_normalize_gdb_paired_unknown_function_names(thread1, thread2); } dist = sr_distance(dist_type, (struct sr_thread*)thread1, (struct sr_thread*)thread2); if (ok != all) { sr_gdb_thread_free(thread1); sr_gdb_thread_free(thread2); } } else dist = sr_distance(dist_type, threads[i], threads[j]); distances->distances[get_distance_position(distances, i, j)] = dist; } } return distances; }
static int core_backtrace_is_duplicate(struct sr_stacktrace *bt1, const char *bt2_text) { struct sr_thread *thread1 = sr_stacktrace_find_crash_thread(bt1); if (thread1 == NULL) { log_notice("New stacktrace has no crash thread, disabling core stacktrace deduplicate"); dup_corebt_fini(); return 0; } int result; char *error_message; struct sr_stacktrace *bt2 = sr_stacktrace_parse(sr_abrt_type_from_analyzer(analyzer), bt2_text, &error_message); if (bt2 == NULL) { log_notice("Failed to parse backtrace, considering it not duplicate: %s", error_message); free(error_message); return 0; } struct sr_thread *thread2 = sr_stacktrace_find_crash_thread(bt2); if (thread2 == NULL) { log_notice("Failed to get crash thread, considering it not duplicate"); result = 0; goto end; } int length2 = sr_thread_frame_count(thread2); if (length2 <= 0) { log_notice("Core backtrace has zero frames, considering it not duplicate"); result = 0; goto end; } /* This is an ugly workaround for https://github.com/abrt/btparser/issues/6 */ /* int length1 = sr_core_thread_get_frame_count(thread1); if (length1 <= 2 || length2 <= 2) { log_notice("Backtraces too short, falling back on full comparison"); result = (sr_core_thread_cmp(thread1, thread2) == 0); goto end; } */ float distance = sr_distance(SR_DISTANCE_DAMERAU_LEVENSHTEIN, thread1, thread2); log_info("Distance between backtraces: %f", distance); result = (distance <= BACKTRACE_DUP_THRESHOLD); end: sr_stacktrace_free(bt2); return result; }