+static void free_p(struct btrace_pid *p)
+{
+ struct btrace_out *o = &p->o;
+ int i;
+
+ for (i = 0; i < p->nr_files; i++) {
+ if (p->files[i].name && p->files[i].name != filename)
+ free(p->files[i].name);
+ }
+
+ for (i = 0; i < DDIR_RWDIR_CNT; i++)
+ free(o->bs[i]);
+
+ free(p->files);
+ flist_del(&p->pid_list);
+ flist_del(&p->hash_list);
+ free(p);
+}
+
+static int entries_close(struct btrace_pid *pida, struct btrace_pid *pidb)
+{
+ float perca, percb, fdiff;
+ int i, idiff;
+
+ for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+ if ((pida->o.ios[i] && !pidb->o.ios[i]) ||
+ (pidb->o.ios[i] && !pida->o.ios[i]))
+ return 0;
+ if (pida->o.ios[i] && pidb->o.ios[i]) {
+ perca = ((float) pida->o.seq[i] * 100.0) / (float) pida->o.ios[i];
+ percb = ((float) pidb->o.seq[i] * 100.0) / (float) pidb->o.ios[i];
+ fdiff = perca - percb;
+ if (fabs(fdiff) > random_diff)
+ return 0;
+ }
+
+ idiff = pida->o.depth - pidb->o.depth;
+ if (abs(idiff) > depth_diff)
+ return 0;
+ }
+
+ return 1;
+}
+
+static void merge_bs(struct bs **bsap, unsigned int *nr_bsap,
+ struct bs *bsb, unsigned int nr_bsb)
+{
+ struct bs *bsa = *bsap;
+ unsigned int nr_bsa = *nr_bsap;
+ int a, b;
+
+ for (b = 0; b < nr_bsb; b++) {
+ int next, found = 0;
+
+ for (a = 0; a < nr_bsa; a++) {
+ if (bsb[b].bs != bsa[a].bs)
+ continue;
+
+ bsa[a].nr += bsb[b].nr;
+ bsa[a].merges += bsb[b].merges;
+ found = 1;
+ break;
+ }
+
+ if (found)
+ continue;
+
+ next = *nr_bsap;
+ bsa = realloc(bsa, (next + 1) * sizeof(struct bs));
+ bsa[next].bs = bsb[b].bs;
+ bsa[next].nr = bsb[b].nr;
+ (*nr_bsap)++;
+ *bsap = bsa;
+ }
+}
+
+static int merge_entries(struct btrace_pid *pida, struct btrace_pid *pidb)
+{
+ int i;
+
+ if (!entries_close(pida, pidb))
+ return 0;
+
+ pida->nr_merge_pids++;
+ pida->merge_pids = realloc(pida->merge_pids, pida->nr_merge_pids * sizeof(pid_t));
+ pida->merge_pids[pida->nr_merge_pids - 1] = pidb->pid;
+
+ for (i = 0; i < DDIR_RWDIR_CNT; i++) {
+ struct btrace_out *oa = &pida->o;
+ struct btrace_out *ob = &pidb->o;
+
+ oa->ios[i] += ob->ios[i];
+ oa->merges[i] += ob->merges[i];
+ oa->seq[i] += ob->seq[i];
+ oa->kib[i] += ob->kib[i];
+ oa->first_ttime[i] = min(oa->first_ttime[i], ob->first_ttime[i]);
+ oa->last_ttime[i] = max(oa->last_ttime[i], ob->last_ttime[i]);
+ merge_bs(&oa->bs[i], &oa->nr_bs[i], ob->bs[i], ob->nr_bs[i]);
+ }
+
+ pida->o.start_delay = min(pida->o.start_delay, pidb->o.start_delay);
+ pida->o.depth = (pida->o.depth + pidb->o.depth) / 2;
+ return 1;
+}
+
+static void check_merges(struct btrace_pid *p, struct flist_head *pidlist)
+{
+ struct flist_head *e, *tmp;
+
+ if (p->ignore)
+ return;
+
+ flist_for_each_safe(e, tmp, pidlist) {
+ struct btrace_pid *pidb;
+
+ pidb = flist_entry(e, struct btrace_pid, pid_list);
+ if (pidb == p)
+ continue;
+
+ if (merge_entries(p, pidb)) {
+ pidb->ignore = 1;
+ p->numjobs++;
+ }
+ }
+}
+