struct sr_distances * sr_distances_dup(struct sr_distances *distances) { struct sr_distances *dup_distances; dup_distances = sr_distances_new(distances->m, distances->n); memcpy(dup_distances->distances, distances->distances, sizeof(*distances->distances) * (get_distance_position(distances, distances->m - 1, distances->n - 1) + 1)); return dup_distances; }
float sr_distances_get_distance(struct sr_distances *distances, int i, int j) { if (i == j) return 0.0; if (i > j) { int x; x = j, j = i, i = x; } return distances->distances[get_distance_position(distances, i, j)]; }
void btp_distances_set_distance(struct btp_distances *distances, int i, int j, float d) { if (i == j) return; if (i > j) { int x; x = j, j = i, i = x; } distances->distances[get_distance_position(distances, i, j)] = d; }
struct btp_distances * btp_distances_new(int m, int n) { struct btp_distances *distances = btp_malloc(sizeof(struct btp_distances)); /* The number of rows has to be smaller than columns. */ if (m >= n) m = n - 1; assert(m > 0 && n > 1 && m < n); distances->m = m; distances->n = n; distances->distances = btp_malloc(sizeof(*distances->distances) * (get_distance_position(distances, m - 1, n - 1) + 1)); return distances; }
struct btp_distances * btp_threads_compare(struct btp_thread **threads, int m, int n, btp_dist_thread_type dist_func) { struct btp_distances *distances; struct btp_thread *thread1, *thread2; int i, j, ok, all; distances = btp_distances_new(m, n); for (i = 0; i < m; i++) for (j = i + 1; j < n; j++) { ok = all = 0; btp_thread_quality_counts(threads[i], &ok, &all); btp_thread_quality_counts(threads[j], &ok, &all); if (ok == all) { thread1 = threads[i]; thread2 = threads[j]; } else { /* There are some unknown function names, try to pair them, but * the threads need to be copied first. */ thread1 = btp_thread_dup(threads[i], false); thread2 = btp_thread_dup(threads[j], false); btp_normalize_paired_unknown_function_names(thread1, thread2); } distances->distances[get_distance_position(distances, i, j)] = dist_func(thread1, thread2); if (ok != all) { btp_thread_free(thread1); btp_thread_free(thread2); } } return distances; }
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; }