blame: large-scale performance rewrite

The previous implementation used a single sorted linear list of blame entries for organizing all partial or completed work. Every subtask had to scan the whole list, with most entries not being relevant to the task. The resulting run-time was quadratic to the number of separate chunks. This change gives every subtask its own data to work with. Subtasks are organized into "struct origin" chains hanging off particular commits. Commits are organized into a priority queue, processing them in commit date order in order to keep most of the work affecting a particular blob collated even in the presence of an extensive merge history. For large files with a diversified history, a speedup by a factor of 3 or more is not unusual. Signed-off-by: David Kastrup <dak@gnu.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

David Kastrup committed Apr 26, 2014 at 01:56 UTC 7e6ac6e4391caa0fc379cb699013d503380e4214
1 file changed +567 -298
builtin/blame.c
+567 -298
@@ -1,7 +1,8 @@
1 /*
2 * Blame
3 *
4 - * Copyright (c) 2006, Junio C Hamano
4 + * Copyright (c) 2006, 2014 by its authors
5 + * See COPYING for licensing conditions
6 */
7
8 #include "cache.h"
@@ -18,7 +19,9 @@
19 #include "cache-tree.h"
20 #include "string-list.h"
21 #include "mailmap.h"
22 +#include "mergesort.h"
23 #include "parse-options.h"
24 +#include "prio-queue.h"
25 #include "utf8.h"
26 #include "userdiff.h"
27 #include "line-range.h"
@@ -83,11 +86,42 @@ static unsigned blame_copy_score;
86 */
87 struct origin {
88 int refcnt;
89 + /* Record preceding blame record for this blob */
90 struct origin *previous;
91 + /* origins are put in a list linked via `next' hanging off the
92 + * corresponding commit's util field in order to make finding
93 + * them fast. The presence in this chain does not count
94 + * towards the origin's reference count. It is tempting to
95 + * let it count as long as the commit is pending examination,
96 + * but even under circumstances where the commit will be
97 + * present multiple times in the priority queue of unexamined
98 + * commits, processing the first instance will not leave any
99 + * work requiring the origin data for the second instance. An
100 + * interspersed commit changing that would have to be
101 + * preexisting with a different ancestry and with the same
102 + * commit date in order to wedge itself between two instances
103 + * of the same commit in the priority queue _and_ produce
104 + * blame entries relevant for it. While we don't want to let
105 + * us get tripped up by this case, it certainly does not seem
106 + * worth optimizing for.
107 + */
108 + struct origin *next;
109 struct commit *commit;
110 + /* `suspects' contains blame entries that may be attributed to
111 + * this origin's commit or to parent commits. When a commit
112 + * is being processed, all suspects will be moved, either by
113 + * assigning them to an origin in a different commit, or by
114 + * shipping them to the scoreboard's ent list because they
115 + * cannot be attributed to a different commit.
116 + */
117 + struct blame_entry *suspects;
118 mmfile_t file;
119 unsigned char blob_sha1[20];
120 unsigned mode;
121 + /* guilty gets set when shipping any suspects to the final
122 + * blame list instead of other commits
123 + */
124 + char guilty;
125 char path[FLEX_ARRAY];
126 };
127
@@ -176,10 +210,22 @@ static inline struct origin *origin_incref(struct origin *o)
210 static void origin_decref(struct origin *o)
211 {
212 if (o && --o->refcnt <= 0) {
213 + struct origin *p, *l = NULL;
214 if (o->previous)
215 origin_decref(o->previous);
216 free(o->file.ptr);
182 - free(o);
217 + /* Should be present exactly once in commit chain */
218 + for (p = o->commit->util; p; l = p, p = p->next) {
219 + if (p == o) {
220 + if (l)
221 + l->next = p->next;
222 + else
223 + o->commit->util = p->next;
224 + free(o);
225 + return;
226 + }
227 + }
228 + die("internal error in blame::origin_decref");
229 }
230 }
231
@@ -193,8 +239,12 @@ static void drop_origin_blob(struct origin *o)
239
240 /*
241 * Each group of lines is described by a blame_entry; it can be split
196 - * as we pass blame to the parents. They form a linked list in the
197 - * scoreboard structure, sorted by the target line number.
242 + * as we pass blame to the parents. They are arranged in linked lists
243 + * kept as `suspects' of some unprocessed origin, or entered (when the
244 + * blame origin has been finalized) into the scoreboard structure.
245 + * While the scoreboard structure is only sorted at the end of
246 + * processing (according to final image line number), the lists
247 + * attached to an origin are sorted by the target line number.
248 */
249 struct blame_entry {
250 struct blame_entry *next;
@@ -210,15 +260,6 @@ struct blame_entry {
260 /* the commit that introduced this group into the final image */
261 struct origin *suspect;
262
213 - /* true if the suspect is truly guilty; false while we have not
214 - * checked if the group came from one of its parents.
215 - */
216 - char guilty;
217 -
218 - /* true if the entry has been scanned for copies in the current parent
219 - */
220 - char scanned;
221 -
263 /* the line number of the first line of this group in the
264 * suspect's file; internally all line numbers are 0 based.
265 */
@@ -230,12 +271,113 @@ struct blame_entry {
271 unsigned score;
272 };
273
274 +/*
275 + * Any merge of blames happens on lists of blames that arrived via
276 + * different parents in a single suspect. In this case, we want to
277 + * sort according to the suspect line numbers as opposed to the final
278 + * image line numbers. The function body is somewhat longish because
279 + * it avoids unnecessary writes.
280 + */
281 +
282 +static struct blame_entry *blame_merge(struct blame_entry *list1,
283 + struct blame_entry *list2)
284 +{
285 + struct blame_entry *p1 = list1, *p2 = list2,
286 + **tail = &list1;
287 +
288 + if (!p1)
289 + return p2;
290 + if (!p2)
291 + return p1;
292 +
293 + if (p1->s_lno <= p2->s_lno) {
294 + do {
295 + tail = &p1->next;
296 + if ((p1 = *tail) == NULL) {
297 + *tail = p2;
298 + return list1;
299 + }
300 + } while (p1->s_lno <= p2->s_lno);
301 + }
302 + for (;;) {
303 + *tail = p2;
304 + do {
305 + tail = &p2->next;
306 + if ((p2 = *tail) == NULL) {
307 + *tail = p1;
308 + return list1;
309 + }
310 + } while (p1->s_lno > p2->s_lno);
311 + *tail = p1;
312 + do {
313 + tail = &p1->next;
314 + if ((p1 = *tail) == NULL) {
315 + *tail = p2;
316 + return list1;
317 + }
318 + } while (p1->s_lno <= p2->s_lno);
319 + }
320 +}
321 +
322 +static void *get_next_blame(const void *p)
323 +{
324 + return ((struct blame_entry *)p)->next;
325 +}
326 +
327 +static void set_next_blame(void *p1, void *p2)
328 +{
329 + ((struct blame_entry *)p1)->next = p2;
330 +}
331 +
332 +/*
333 + * Final image line numbers are all different, so we don't need a
334 + * three-way comparison here.
335 + */
336 +
337 +static int compare_blame_final(const void *p1, const void *p2)
338 +{
339 + return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno
340 + ? 1 : -1;
341 +}
342 +
343 +static int compare_blame_suspect(const void *p1, const void *p2)
344 +{
345 + const struct blame_entry *s1 = p1, *s2 = p2;
346 + /*
347 + * to allow for collating suspects, we sort according to the
348 + * respective pointer value as the primary sorting criterion.
349 + * The actual relation is pretty unimportant as long as it
350 + * establishes a total order. Comparing as integers gives us
351 + * that.
352 + */
353 + if (s1->suspect != s2->suspect)
354 + return (intptr_t)s1->suspect > (intptr_t)s2->suspect ? 1 : -1;
355 + if (s1->s_lno == s2->s_lno)
356 + return 0;
357 + return s1->s_lno > s2->s_lno ? 1 : -1;
358 +}
359 +
360 +static struct blame_entry *blame_sort(struct blame_entry *head,
361 + int (*compare_fn)(const void *, const void *))
362 +{
363 + return llist_mergesort (head, get_next_blame, set_next_blame, compare_fn);
364 +}
365 +
366 +static int compare_commits_by_reverse_commit_date(const void *a,
367 + const void *b,
368 + void *c)
369 +{
370 + return -compare_commits_by_commit_date(a, b, c);
371 +}
372 +
373 /*
374 * The current state of the blame assignment.
375 */
376 struct scoreboard {
377 /* the final commit (i.e. where we started digging from) */
378 struct commit *final;
379 + /* Priority queue for commits with unassigned blame records */
380 + struct prio_queue commits;
381 struct rev_info *revs;
382 const char *path;
383
@@ -268,7 +410,6 @@ static void coalesce(struct scoreboard *sb)
410
411 for (ent = sb->ent; ent && (next = ent->next); ent = next) {
412 if (ent->suspect == next->suspect &&
271 - ent->guilty == next->guilty &&
413 ent->s_lno + ent->num_lines == next->s_lno) {
414 ent->num_lines += next->num_lines;
415 ent->next = next->next;
@@ -283,6 +424,30 @@ static void coalesce(struct scoreboard *sb)
424 sanity_check_refcnt(sb);
425 }
426
427 +/*
428 + * Merge the given sorted list of blames into a preexisting origin.
429 + * If there were no previous blames to that commit, it is entered into
430 + * the commit priority queue of the score board.
431 + */
432 +
433 +static void queue_blames(struct scoreboard *sb, struct origin *porigin,
434 + struct blame_entry *sorted)
435 +{
436 + if (porigin->suspects)
437 + porigin->suspects = blame_merge(porigin->suspects, sorted);
438 + else {
439 + struct origin *o;
440 + for (o = porigin->commit->util; o; o = o->next) {
441 + if (o->suspects) {
442 + porigin->suspects = sorted;
443 + return;
444 + }
445 + }
446 + porigin->suspects = sorted;
447 + prio_queue_put(&sb->commits, porigin->commit);
448 + }
449 +}
450 +
451 /*
452 * Given a commit and a path in it, create a new origin structure.
453 * The callers that add blame to the scoreboard should use
@@ -295,23 +460,32 @@ static struct origin *make_origin(struct commit *commit, const char *path)
460 o = xcalloc(1, sizeof(*o) + strlen(path) + 1);
461 o->commit = commit;
462 o->refcnt = 1;
463 + o->next = commit->util;
464 + commit->util = o;
465 strcpy(o->path, path);
466 return o;
467 }
468
469 /*
470 * Locate an existing origin or create a new one.
471 + * This moves the origin to front position in the commit util list.
472 */
473 static struct origin *get_origin(struct scoreboard *sb,
474 struct commit *commit,
475 const char *path)
476 {
309 - struct blame_entry *e;
477 + struct origin *o, *l;
478
311 - for (e = sb->ent; e; e = e->next) {
312 - if (e->suspect->commit == commit &&
313 - !strcmp(e->suspect->path, path))
314 - return origin_incref(e->suspect);
479 + for (o = commit->util, l = NULL; o; l = o, o = o->next) {
480 + if (!strcmp(o->path, path)) {
481 + /* bump to front */
482 + if (l) {
483 + l->next = o->next;
484 + o->next = commit->util;
485 + commit->util = o;
486 + }
487 + return origin_incref(o);
488 + }
489 }
490 return make_origin(commit, path);
491 }
@@ -350,41 +524,19 @@ static struct origin *find_origin(struct scoreboard *sb,
524 struct commit *parent,
525 struct origin *origin)
526 {
353 - struct origin *porigin = NULL;
527 + struct origin *porigin;
528 struct diff_options diff_opts;
529 const char *paths[2];
530
357 - if (parent->util) {
358 - /*
359 - * Each commit object can cache one origin in that
360 - * commit. This is a freestanding copy of origin and
361 - * not refcounted.
362 - */
363 - struct origin *cached = parent->util;
364 - if (!strcmp(cached->path, origin->path)) {
531 + /* First check any existing origins */
532 + for (porigin = parent->util; porigin; porigin = porigin->next)
533 + if (!strcmp(porigin->path, origin->path)) {
534 /*
535 * The same path between origin and its parent
536 * without renaming -- the most common case.
537 */
369 - porigin = get_origin(sb, parent, cached->path);
370 -
371 - /*
372 - * If the origin was newly created (i.e. get_origin
373 - * would call make_origin if none is found in the
374 - * scoreboard), it does not know the blob_sha1/mode,
375 - * so copy it. Otherwise porigin was in the
376 - * scoreboard and already knows blob_sha1/mode.
377 - */
378 - if (porigin->refcnt == 1) {
379 - hashcpy(porigin->blob_sha1, cached->blob_sha1);
380 - porigin->mode = cached->mode;
381 - }
382 - return porigin;
538 + return origin_incref (porigin);
539 }
384 - /* otherwise it was not very useful; free it */
385 - free(parent->util);
386 - parent->util = NULL;
387 - }
540
541 /* See if the origin->path is different between parent
542 * and origin first. Most of the time they are the
@@ -450,19 +602,6 @@ static struct origin *find_origin(struct scoreboard *sb,
602 }
603 diff_flush(&diff_opts);
604 free_pathspec(&diff_opts.pathspec);
453 - if (porigin) {
454 - /*
455 - * Create a freestanding copy that is not part of
456 - * the refcounted origin found in the scoreboard, and
457 - * cache it in the commit.
458 - */
459 - struct origin *cached;
460 -
461 - cached = make_origin(porigin->commit, porigin->path);
462 - hashcpy(cached->blob_sha1, porigin->blob_sha1);
463 - cached->mode = porigin->mode;
464 - parent->util = cached;
465 - }
605 return porigin;
606 }
607
@@ -509,46 +648,31 @@ static struct origin *find_rename(struct scoreboard *sb,
648 }
649
650 /*
512 - * Link in a new blame entry to the scoreboard. Entries that cover the
513 - * same line range have been removed from the scoreboard previously.
651 + * Append a new blame entry to a given output queue.
652 */
515 -static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
653 +static void add_blame_entry(struct blame_entry ***queue, struct blame_entry *e)
654 {
517 - struct blame_entry *ent, *prev = NULL;
518 -
655 origin_incref(e->suspect);
656
521 - for (ent = sb->ent; ent && ent->lno < e->lno; ent = ent->next)
522 - prev = ent;
523 -
524 - /* prev, if not NULL, is the last one that is below e */
525 -
526 - if (prev) {
527 - e->next = prev->next;
528 - prev->next = e;
529 - }
530 - else {
531 - e->next = sb->ent;
532 - sb->ent = e;
533 - }
657 + e->next = **queue;
658 + **queue = e;
659 + *queue = &e->next;
660 }
661
662 /*
663 * src typically is on-stack; we want to copy the information in it to
538 - * a malloced blame_entry that is already on the linked list of the
539 - * scoreboard. The origin of dst loses a refcnt while the origin of src
540 - * gains one.
664 + * a malloced blame_entry that gets added to the given queue. The
665 + * origin of dst loses a refcnt.
666 */
542 -static void dup_entry(struct blame_entry *dst, struct blame_entry *src)
667 +static void dup_entry(struct blame_entry ***queue,
668 + struct blame_entry *dst, struct blame_entry *src)
669 {
544 - struct blame_entry *n;
545 -
546 - n = dst->next;
670 origin_incref(src->suspect);
671 origin_decref(dst->suspect);
672 memcpy(dst, src, sizeof(*src));
550 - dst->next = n;
551 - dst->score = 0;
673 + dst->next = **queue;
674 + **queue = dst;
675 + *queue = &dst->next;
676 }
677
678 static const char *nth_line(struct scoreboard *sb, long lno)
@@ -620,10 +744,11 @@ static void split_overlap(struct blame_entry *split,
744
745 /*
746 * split_overlap() divided an existing blame e into up to three parts
623 - * in split. Adjust the linked list of blames in the scoreboard to
747 + * in split. Any assigned blame is moved to queue to
748 * reflect the split.
749 */
626 -static void split_blame(struct scoreboard *sb,
750 +static void split_blame(struct blame_entry ***blamed,
751 + struct blame_entry ***unblamed,
752 struct blame_entry *split,
753 struct blame_entry *e)
754 {
@@ -631,61 +756,39 @@ static void split_blame(struct scoreboard *sb,
756
757 if (split[0].suspect && split[2].suspect) {
758 /* The first part (reuse storage for the existing entry e) */
634 - dup_entry(e, &split[0]);
759 + dup_entry(unblamed, e, &split[0]);
760
761 /* The last part -- me */
762 new_entry = xmalloc(sizeof(*new_entry));
763 memcpy(new_entry, &(split[2]), sizeof(struct blame_entry));
639 - add_blame_entry(sb, new_entry);
764 + add_blame_entry(unblamed, new_entry);
765
766 /* ... and the middle part -- parent */
767 new_entry = xmalloc(sizeof(*new_entry));
768 memcpy(new_entry, &(split[1]), sizeof(struct blame_entry));
644 - add_blame_entry(sb, new_entry);
769 + add_blame_entry(blamed, new_entry);
770 }
771 else if (!split[0].suspect && !split[2].suspect)
772 /*
773 * The parent covers the entire area; reuse storage for
774 * e and replace it with the parent.
775 */
651 - dup_entry(e, &split[1]);
776 + dup_entry(blamed, e, &split[1]);
777 else if (split[0].suspect) {
778 /* me and then parent */
654 - dup_entry(e, &split[0]);
779 + dup_entry(unblamed, e, &split[0]);
780
781 new_entry = xmalloc(sizeof(*new_entry));
782 memcpy(new_entry, &(split[1]), sizeof(struct blame_entry));
658 - add_blame_entry(sb, new_entry);
783 + add_blame_entry(blamed, new_entry);
784 }
785 else {
786 /* parent and then me */
662 - dup_entry(e, &split[1]);
787 + dup_entry(blamed, e, &split[1]);
788
789 new_entry = xmalloc(sizeof(*new_entry));
790 memcpy(new_entry, &(split[2]), sizeof(struct blame_entry));
666 - add_blame_entry(sb, new_entry);
667 - }
668 -
669 - if (DEBUG) { /* sanity */
670 - struct blame_entry *ent;
671 - int lno = sb->ent->lno, corrupt = 0;
672 -
673 - for (ent = sb->ent; ent; ent = ent->next) {
674 - if (lno != ent->lno)
675 - corrupt = 1;
676 - if (ent->s_lno < 0)
677 - corrupt = 1;
678 - lno += ent->num_lines;
679 - }
680 - if (corrupt) {
681 - lno = sb->ent->lno;
682 - for (ent = sb->ent; ent; ent = ent->next) {
683 - printf("L %8d l %8d n %8d\n",
684 - lno, ent->lno, ent->num_lines);
685 - lno = ent->lno + ent->num_lines;
686 - }
687 - die("oops");
688 - }
791 + add_blame_entry(unblamed, new_entry);
792 }
793 }
794
@@ -702,74 +805,146 @@ static void decref_split(struct blame_entry *split)
805 }
806
807 /*
705 - * Helper for blame_chunk(). blame_entry e is known to overlap with
706 - * the patch hunk; split it and pass blame to the parent.
808 + * reverse_blame reverses the list given in head, appending tail.
809 + * That allows us to build lists in reverse order, then reverse them
810 + * afterwards. This can be faster than building the list in proper
811 + * order right away. The reason is that building in proper order
812 + * requires writing a link in the _previous_ element, while building
813 + * in reverse order just requires placing the list head into the
814 + * _current_ element.
815 */
708 -static void blame_overlap(struct scoreboard *sb, struct blame_entry *e,
709 - int tlno, int plno, int same,
710 - struct origin *parent)
711 -{
712 - struct blame_entry split[3];
713 -
714 - split_overlap(split, e, tlno, plno, same, parent);
715 - if (split[1].suspect)
716 - split_blame(sb, split, e);
717 - decref_split(split);
718 -}
816
720 -/*
721 - * Find the line number of the last line the target is suspected for.
722 - */
723 -static int find_last_in_target(struct scoreboard *sb, struct origin *target)
817 +static struct blame_entry *reverse_blame(struct blame_entry *head,
818 + struct blame_entry *tail)
819 {
725 - struct blame_entry *e;
726 - int last_in_target = -1;
727 -
728 - for (e = sb->ent; e; e = e->next) {
729 - if (e->guilty || e->suspect != target)
730 - continue;
731 - if (last_in_target < e->s_lno + e->num_lines)
732 - last_in_target = e->s_lno + e->num_lines;
820 + while (head) {
821 + struct blame_entry *next = head->next;
822 + head->next = tail;
823 + tail = head;
824 + head = next;
825 }
734 - return last_in_target;
826 + return tail;
827 }
828
829 /*
830 * Process one hunk from the patch between the current suspect for
739 - * blame_entry e and its parent. Find and split the overlap, and
740 - * pass blame to the overlapping part to the parent.
831 + * blame_entry e and its parent. This first blames any unfinished
832 + * entries before the chunk (which is where target and parent start
833 + * differing) on the parent, and then splits blame entries at the
834 + * start and at the end of the difference region. Since use of -M and
835 + * -C options may lead to overlapping/duplicate source line number
836 + * ranges, all we can rely on from sorting/merging is the order of the
837 + * first suspect line number.
838 */
742 -static void blame_chunk(struct scoreboard *sb,
743 - int tlno, int plno, int same,
744 - struct origin *target, struct origin *parent)
839 +static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq,
840 + int tlno, int offset, int same,
841 + struct origin *parent)
842 {
746 - struct blame_entry *e;
843 + struct blame_entry *e = **srcq;
844 + struct blame_entry *samep = NULL, *diffp = NULL;
845
748 - for (e = sb->ent; e; e = e->next) {
749 - if (e->guilty || e->suspect != target)
750 - continue;
751 - if (same <= e->s_lno)
752 - continue;
753 - if (tlno < e->s_lno + e->num_lines)
754 - blame_overlap(sb, e, tlno, plno, same, parent);
846 + while (e && e->s_lno < tlno) {
847 + struct blame_entry *next = e->next;
848 + /*
849 + * current record starts before differing portion. If
850 + * it reaches into it, we need to split it up and
851 + * examine the second part separately.
852 + */
853 + if (e->s_lno + e->num_lines > tlno) {
854 + /* Move second half to a new record */
855 + int len = tlno - e->s_lno;
856 + struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry));
857 + n->suspect = e->suspect;
858 + n->lno = e->lno + len;
859 + n->s_lno = e->s_lno + len;
860 + n->num_lines = e->num_lines - len;
861 + e->num_lines = len;
862 + e->score = 0;
863 + /* Push new record to diffp */
864 + n->next = diffp;
865 + diffp = n;
866 + } else
867 + origin_decref(e->suspect);
868 + /* Pass blame for everything before the differing
869 + * chunk to the parent */
870 + e->suspect = origin_incref(parent);
871 + e->s_lno += offset;
872 + e->next = samep;
873 + samep = e;
874 + e = next;
875 + }
876 + /*
877 + * As we don't know how much of a common stretch after this
878 + * diff will occur, the currently blamed parts are all that we
879 + * can assign to the parent for now.
880 + */
881 +
882 + if (samep) {
883 + **dstq = reverse_blame(samep, **dstq);
884 + *dstq = &samep->next;
885 }
886 + /*
887 + * Prepend the split off portions: everything after e starts
888 + * after the blameable portion.
889 + */
890 + e = reverse_blame(diffp, e);
891 +
892 + /*
893 + * Now retain records on the target while parts are different
894 + * from the parent.
895 + */
896 + samep = NULL;
897 + diffp = NULL;
898 + while (e && e->s_lno < same) {
899 + struct blame_entry *next = e->next;
900 +
901 + /*
902 + * If current record extends into sameness, need to split.
903 + */
904 + if (e->s_lno + e->num_lines > same) {
905 + /*
906 + * Move second half to a new record to be
907 + * processed by later chunks
908 + */
909 + int len = same - e->s_lno;
910 + struct blame_entry *n = xcalloc(1, sizeof (struct blame_entry));
911 + n->suspect = origin_incref(e->suspect);
912 + n->lno = e->lno + len;
913 + n->s_lno = e->s_lno + len;
914 + n->num_lines = e->num_lines - len;
915 + e->num_lines = len;
916 + e->score = 0;
917 + /* Push new record to samep */
918 + n->next = samep;
919 + samep = n;
920 + }
921 + e->next = diffp;
922 + diffp = e;
923 + e = next;
924 + }
925 + **srcq = reverse_blame(diffp, reverse_blame(samep, e));
926 + /* Move across elements that are in the unblamable portion */
927 + if (diffp)
928 + *srcq = &diffp->next;
929 }
930
931 struct blame_chunk_cb_data {
759 - struct scoreboard *sb;
760 - struct origin *target;
932 struct origin *parent;
762 - long plno;
763 - long tlno;
933 + long offset;
934 + struct blame_entry **dstq;
935 + struct blame_entry **srcq;
936 };
937
938 +/* diff chunks are from parent to target */
939 static int blame_chunk_cb(long start_a, long count_a,
940 long start_b, long count_b, void *data)
941 {
942 struct blame_chunk_cb_data *d = data;
770 - blame_chunk(d->sb, d->tlno, d->plno, start_b, d->target, d->parent);
771 - d->plno = start_a + count_a;
772 - d->tlno = start_b + count_b;
943 + if (start_a - start_b != d->offset)
944 + die("internal error in blame::blame_chunk_cb");
945 + blame_chunk(&d->dstq, &d->srcq, start_b, start_a - start_b,
946 + start_b + count_b, d->parent);
947 + d->offset = start_a + count_a - (start_b + count_b);
948 return 0;
949 }
950
@@ -778,29 +953,32 @@ static int blame_chunk_cb(long start_a, long count_a,
953 * for the lines it is suspected to its parent. Run diff to find
954 * which lines came from parent and pass blame for them.
955 */
781 -static int pass_blame_to_parent(struct scoreboard *sb,
782 - struct origin *target,
783 - struct origin *parent)
956 +static void pass_blame_to_parent(struct scoreboard *sb,
957 + struct origin *target,
958 + struct origin *parent)
959 {
785 - int last_in_target;
960 mmfile_t file_p, file_o;
961 struct blame_chunk_cb_data d;
962 + struct blame_entry *newdest = NULL;
963
789 - memset(&d, 0, sizeof(d));
790 - d.sb = sb; d.target = target; d.parent = parent;
791 - last_in_target = find_last_in_target(sb, target);
792 - if (last_in_target < 0)
793 - return 1; /* nothing remains for this target */
964 + if (!target->suspects)
965 + return; /* nothing remains for this target */
966 +
967 + d.parent = parent;
968 + d.offset = 0;
969 + d.dstq = &newdest; d.srcq = &target->suspects;
970
971 fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
972 fill_origin_blob(&sb->revs->diffopt, target, &file_o);
973 num_get_patch++;
974
975 diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);
800 - /* The rest (i.e. anything after tlno) are the same as the parent */
801 - blame_chunk(sb, d.tlno, d.plno, last_in_target, target, parent);
976 + /* The rest are the same as the parent */
977 + blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent);
978 + *d.dstq = NULL;
979 + queue_blames(sb, parent, newdest);
980
803 - return 0;
981 + return;
982 }
983
984 /*
@@ -945,43 +1123,80 @@ static void find_copy_in_blob(struct scoreboard *sb,
1123 handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
1124 }
1125
1126 +/* Move all blame entries from list *source that have a score smaller
1127 + * than score_min to the front of list *small.
1128 + * Returns a pointer to the link pointing to the old head of the small list.
1129 + */
1130 +
1131 +static struct blame_entry **filter_small(struct scoreboard *sb,
1132 + struct blame_entry **small,
1133 + struct blame_entry **source,
1134 + unsigned score_min)
1135 +{
1136 + struct blame_entry *p = *source;
1137 + struct blame_entry *oldsmall = *small;
1138 + while (p) {
1139 + if (ent_score(sb, p) <= score_min) {
1140 + *small = p;
1141 + small = &p->next;
1142 + p = *small;
1143 + } else {
1144 + *source = p;
1145 + source = &p->next;
1146 + p = *source;
1147 + }
1148 + }
1149 + *small = oldsmall;
1150 + *source = NULL;
1151 + return small;
1152 +}
1153 +
1154 /*
1155 * See if lines currently target is suspected for can be attributed to
1156 * parent.
1157 */
952 -static int find_move_in_parent(struct scoreboard *sb,
953 - struct origin *target,
954 - struct origin *parent)
1158 +static void find_move_in_parent(struct scoreboard *sb,
1159 + struct blame_entry ***blamed,
1160 + struct blame_entry **toosmall,
1161 + struct origin *target,
1162 + struct origin *parent)
1163 {
956 - int last_in_target, made_progress;
1164 struct blame_entry *e, split[3];
1165 + struct blame_entry *unblamed = target->suspects;
1166 + struct blame_entry *leftover = NULL;
1167 mmfile_t file_p;
1168
960 - last_in_target = find_last_in_target(sb, target);
961 - if (last_in_target < 0)
962 - return 1; /* nothing remains for this target */
1169 + if (!unblamed)
1170 + return; /* nothing remains for this target */
1171
1172 fill_origin_blob(&sb->revs->diffopt, parent, &file_p);
1173 if (!file_p.ptr)
966 - return 0;
1174 + return;
1175
968 - made_progress = 1;
969 - while (made_progress) {
970 - made_progress = 0;
971 - for (e = sb->ent; e; e = e->next) {
972 - if (e->guilty || e->suspect != target ||
973 - ent_score(sb, e) < blame_move_score)
974 - continue;
1176 + /* At each iteration, unblamed has a NULL-terminated list of
1177 + * entries that have not yet been tested for blame. leftover
1178 + * contains the reversed list of entries that have been tested
1179 + * without being assignable to the parent.
1180 + */
1181 + do {
1182 + struct blame_entry **unblamedtail = &unblamed;
1183 + struct blame_entry *next;
1184 + for (e = unblamed; e; e = next) {
1185 + next = e->next;
1186 find_copy_in_blob(sb, e, parent, split, &file_p);
1187 if (split[1].suspect &&
1188 blame_move_score < ent_score(sb, &split[1])) {
978 - split_blame(sb, split, e);
979 - made_progress = 1;
1189 + split_blame(blamed, &unblamedtail, split, e);
1190 + } else {
1191 + e->next = leftover;
1192 + leftover = e;
1193 }
1194 decref_split(split);
1195 }
983 - }
984 - return 0;
1196 + *unblamedtail = NULL;
1197 + toosmall = filter_small(sb, toosmall, &unblamed, blame_move_score);
1198 + } while (unblamed);
1199 + target->suspects = reverse_blame(leftover, NULL);
1200 }
1201
1202 struct blame_list {
@@ -993,62 +1208,46 @@ struct blame_list {
1208 * Count the number of entries the target is suspected for,
1209 * and prepare a list of entry and the best split.
1210 */
996 -static struct blame_list *setup_blame_list(struct scoreboard *sb,
997 - struct origin *target,
998 - int min_score,
1211 +static struct blame_list *setup_blame_list(struct blame_entry *unblamed,
1212 int *num_ents_p)
1213 {
1214 struct blame_entry *e;
1215 int num_ents, i;
1216 struct blame_list *blame_list = NULL;
1217
1005 - for (e = sb->ent, num_ents = 0; e; e = e->next)
1006 - if (!e->scanned && !e->guilty &&
1007 - e->suspect == target &&
1008 - min_score < ent_score(sb, e))
1009 - num_ents++;
1218 + for (e = unblamed, num_ents = 0; e; e = e->next)
1219 + num_ents++;
1220 if (num_ents) {
1221 blame_list = xcalloc(num_ents, sizeof(struct blame_list));
1012 - for (e = sb->ent, i = 0; e; e = e->next)
1013 - if (!e->scanned && !e->guilty &&
1014 - e->suspect == target &&
1015 - min_score < ent_score(sb, e))
1016 - blame_list[i++].ent = e;
1222 + for (e = unblamed, i = 0; e; e = e->next)
1223 + blame_list[i++].ent = e;
1224 }
1225 *num_ents_p = num_ents;
1226 return blame_list;
1227 }
1228
1022 -/*
1023 - * Reset the scanned status on all entries.
1024 - */
1025 -static void reset_scanned_flag(struct scoreboard *sb)
1026 -{
1027 - struct blame_entry *e;
1028 - for (e = sb->ent; e; e = e->next)
1029 - e->scanned = 0;
1030 -}
1031 -
1229 /*
1230 * For lines target is suspected for, see if we can find code movement
1231 * across file boundary from the parent commit. porigin is the path
1232 * in the parent we already tried.
1233 */
1037 -static int find_copy_in_parent(struct scoreboard *sb,
1038 - struct origin *target,
1039 - struct commit *parent,
1040 - struct origin *porigin,
1041 - int opt)
1234 +static void find_copy_in_parent(struct scoreboard *sb,
1235 + struct blame_entry ***blamed,
1236 + struct blame_entry **toosmall,
1237 + struct origin *target,
1238 + struct commit *parent,
1239 + struct origin *porigin,
1240 + int opt)
1241 {
1242 struct diff_options diff_opts;
1243 int i, j;
1045 - int retval;
1244 struct blame_list *blame_list;
1245 int num_ents;
1246 + struct blame_entry *unblamed = target->suspects;
1247 + struct blame_entry *leftover = NULL;
1248
1049 - blame_list = setup_blame_list(sb, target, blame_copy_score, &num_ents);
1050 - if (!blame_list)
1051 - return 1; /* nothing remains for this target */
1249 + if (!unblamed)
1250 + return; /* nothing remains for this target */
1251
1252 diff_setup(&diff_opts);
1253 DIFF_OPT_SET(&diff_opts, RECURSIVE);
@@ -1078,9 +1277,9 @@ static int find_copy_in_parent(struct scoreboard *sb,
1277 if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
1278 diffcore_std(&diff_opts);
1279
1081 - retval = 0;
1082 - while (1) {
1083 - int made_progress = 0;
1280 + do {
1281 + struct blame_entry **unblamedtail = &unblamed;
1282 + blame_list = setup_blame_list(unblamed, &num_ents);
1283
1284 for (i = 0; i < diff_queued_diff.nr; i++) {
1285 struct diff_filepair *p = diff_queued_diff.queue[i];
@@ -1117,27 +1316,21 @@ static int find_copy_in_parent(struct scoreboard *sb,
1316 struct blame_entry *split = blame_list[j].split;
1317 if (split[1].suspect &&
1318 blame_copy_score < ent_score(sb, &split[1])) {
1120 - split_blame(sb, split, blame_list[j].ent);
1121 - made_progress = 1;
1319 + split_blame(blamed, &unblamedtail, split,
1320 + blame_list[j].ent);
1321 + } else {
1322 + blame_list[j].ent->next = leftover;
1323 + leftover = blame_list[j].ent;
1324 }
1123 - else
1124 - blame_list[j].ent->scanned = 1;
1325 decref_split(split);
1326 }
1327 free(blame_list);
1128 -
1129 - if (!made_progress)
1130 - break;
1131 - blame_list = setup_blame_list(sb, target, blame_copy_score, &num_ents);
1132 - if (!blame_list) {
1133 - retval = 1;
1134 - break;
1135 - }
1136 - }
1137 - reset_scanned_flag(sb);
1328 + *unblamedtail = NULL;
1329 + toosmall = filter_small(sb, toosmall, &unblamed, blame_copy_score);
1330 + } while (unblamed);
1331 + target->suspects = reverse_blame(leftover, NULL);
1332 diff_flush(&diff_opts);
1333 free_pathspec(&diff_opts.pathspec);
1140 - return retval;
1334 }
1335
1336 /*
@@ -1147,20 +1340,21 @@ static int find_copy_in_parent(struct scoreboard *sb,
1340 static void pass_whole_blame(struct scoreboard *sb,
1341 struct origin *origin, struct origin *porigin)
1342 {
1150 - struct blame_entry *e;
1343 + struct blame_entry *e, *suspects;
1344
1345 if (!porigin->file.ptr && origin->file.ptr) {
1346 /* Steal its file */
1347 porigin->file = origin->file;
1348 origin->file.ptr = NULL;
1349 }
1157 - for (e = sb->ent; e; e = e->next) {
1158 - if (e->suspect != origin)
1159 - continue;
1350 + suspects = origin->suspects;
1351 + origin->suspects = NULL;
1352 + for (e = suspects; e; e = e->next) {
1353 origin_incref(porigin);
1354 origin_decref(e->suspect);
1355 e->suspect = porigin;
1356 }
1357 + queue_blames(sb, porigin, suspects);
1358 }
1359
1360 /*
@@ -1184,6 +1378,27 @@ static int num_scapegoats(struct rev_info *revs, struct commit *commit)
1378 return cnt;
1379 }
1380
1381 +/* Distribute collected unsorted blames to the respected sorted lists
1382 + * in the various origins.
1383 + */
1384 +static void distribute_blame(struct scoreboard *sb, struct blame_entry *blamed)
1385 +{
1386 + blamed = blame_sort(blamed, compare_blame_suspect);
1387 + while (blamed)
1388 + {
1389 + struct origin *porigin = blamed->suspect;
1390 + struct blame_entry *suspects = NULL;
1391 + do {
1392 + struct blame_entry *next = blamed->next;
1393 + blamed->next = suspects;
1394 + suspects = blamed;
1395 + blamed = next;
1396 + } while (blamed && blamed->suspect == porigin);
1397 + suspects = reverse_blame(suspects, NULL);
1398 + queue_blames(sb, porigin, suspects);
1399 + }
1400 +}
1401 +
1402 #define MAXSG 16
1403
1404 static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
@@ -1194,6 +1409,8 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
1409 struct commit_list *sg;
1410 struct origin *sg_buf[MAXSG];
1411 struct origin *porigin, **sg_origin = sg_buf;
1412 + struct blame_entry *toosmall = NULL;
1413 + struct blame_entry *blames, **blametail = &blames;
1414
1415 num_sg = num_scapegoats(revs, commit);
1416 if (!num_sg)
@@ -1255,38 +1472,71 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
1472 origin_incref(porigin);
1473 origin->previous = porigin;
1474 }
1258 - if (pass_blame_to_parent(sb, origin, porigin))
1475 + pass_blame_to_parent(sb, origin, porigin);
1476 + if (!origin->suspects)
1477 goto finish;
1478 }
1479
1480 /*
1481 * Optionally find moves in parents' files.
1482 */
1265 - if (opt & PICKAXE_BLAME_MOVE)
1266 - for (i = 0, sg = first_scapegoat(revs, commit);
1267 - i < num_sg && sg;
1268 - sg = sg->next, i++) {
1269 - struct origin *porigin = sg_origin[i];
1270 - if (!porigin)
1271 - continue;
1272 - if (find_move_in_parent(sb, origin, porigin))
1273 - goto finish;
1483 + if (opt & PICKAXE_BLAME_MOVE) {
1484 + filter_small(sb, &toosmall, &origin->suspects, blame_move_score);
1485 + if (origin->suspects) {
1486 + for (i = 0, sg = first_scapegoat(revs, commit);
1487 + i < num_sg && sg;
1488 + sg = sg->next, i++) {
1489 + struct origin *porigin = sg_origin[i];
1490 + if (!porigin)
1491 + continue;
1492 + find_move_in_parent(sb, &blametail, &toosmall, origin, porigin);
1493 + if (!origin->suspects)
1494 + break;
1495 + }
1496 }
1497 + }
1498
1499 /*
1500 * Optionally find copies from parents' files.
1501 */
1279 - if (opt & PICKAXE_BLAME_COPY)
1502 + if (opt & PICKAXE_BLAME_COPY) {
1503 + if (blame_copy_score > blame_move_score)
1504 + filter_small(sb, &toosmall, &origin->suspects, blame_copy_score);
1505 + else if (blame_copy_score < blame_move_score) {
1506 + origin->suspects = blame_merge(origin->suspects, toosmall);
1507 + toosmall = NULL;
1508 + filter_small(sb, &toosmall, &origin->suspects, blame_copy_score);
1509 + }
1510 + if (!origin->suspects)
1511 + goto finish;
1512 +
1513 for (i = 0, sg = first_scapegoat(revs, commit);
1514 i < num_sg && sg;
1515 sg = sg->next, i++) {
1516 struct origin *porigin = sg_origin[i];
1284 - if (find_copy_in_parent(sb, origin, sg->item,
1285 - porigin, opt))
1517 + find_copy_in_parent(sb, &blametail, &toosmall,
1518 + origin, sg->item, porigin, opt);
1519 + if (!origin->suspects)
1520 goto finish;
1521 }
1522 + }
1523
1289 - finish:
1524 +finish:
1525 + *blametail = NULL;
1526 + distribute_blame(sb, blames);
1527 + /*
1528 + * prepend toosmall to origin->suspects
1529 + *
1530 + * There is no point in sorting: this ends up on a big
1531 + * unsorted list in the caller anyway.
1532 + */
1533 + if (toosmall) {
1534 + struct blame_entry **tail = &toosmall;
1535 + while (*tail)
1536 + tail = &(*tail)->next;
1537 + *tail = origin->suspects;
1538 + origin->suspects = toosmall;
1539 + }
1540 for (i = 0; i < num_sg; i++) {
1541 if (sg_origin[i]) {
1542 drop_origin_blob(sg_origin[i]);
@@ -1481,14 +1731,11 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)
1731 }
1732
1733 /*
1484 - * The blame_entry is found to be guilty for the range. Mark it
1485 - * as such, and show it in incremental output.
1734 + * The blame_entry is found to be guilty for the range.
1735 + * Show it in incremental output.
1736 */
1737 static void found_guilty_entry(struct blame_entry *ent)
1738 {
1489 - if (ent->guilty)
1490 - return;
1491 - ent->guilty = 1;
1739 if (incremental) {
1740 struct origin *suspect = ent->suspect;
1741
@@ -1502,32 +1749,34 @@ static void found_guilty_entry(struct blame_entry *ent)
1749 }
1750
1751 /*
1505 - * The main loop -- while the scoreboard has lines whose true origin
1506 - * is still unknown, pick one blame_entry, and allow its current
1507 - * suspect to pass blames to its parents.
1508 - */
1752 + * The main loop -- while we have blobs with lines whose true origin
1753 + * is still unknown, pick one blob, and allow its lines to pass blames
1754 + * to its parents. */
1755 static void assign_blame(struct scoreboard *sb, int opt)
1756 {
1757 struct rev_info *revs = sb->revs;
1758 + struct commit *commit = prio_queue_get(&sb->commits);
1759
1513 - while (1) {
1760 + while (commit) {
1761 struct blame_entry *ent;
1515 - struct commit *commit;
1516 - struct origin *suspect = NULL;
1762 + struct origin *suspect = commit->util;
1763
1764 /* find one suspect to break down */
1519 - for (ent = sb->ent; !suspect && ent; ent = ent->next)
1520 - if (!ent->guilty)
1521 - suspect = ent->suspect;
1522 - if (!suspect)
1523 - return; /* all done */
1765 + while (suspect && !suspect->suspects)
1766 + suspect = suspect->next;
1767 +
1768 + if (!suspect) {
1769 + commit = prio_queue_get(&sb->commits);
1770 + continue;
1771 + }
1772 +
1773 + assert(commit == suspect->commit);
1774
1775 /*
1776 * We will use this suspect later in the loop,
1777 * so hold onto it in the meantime.
1778 */
1779 origin_incref(suspect);
1530 - commit = suspect->commit;
1780 parse_commit(commit);
1781 if (reverse ||
1782 (!(commit->object.flags & UNINTERESTING) &&
@@ -1543,9 +1792,22 @@ static void assign_blame(struct scoreboard *sb, int opt)
1792 commit->object.flags |= UNINTERESTING;
1793
1794 /* Take responsibility for the remaining entries */
1546 - for (ent = sb->ent; ent; ent = ent->next)
1547 - if (ent->suspect == suspect)
1795 + ent = suspect->suspects;
1796 + if (ent) {
1797 + suspect->guilty = 1;
1798 + for (;;) {
1799 + struct blame_entry *next = ent->next;
1800 found_guilty_entry(ent);
1801 + if (next) {
1802 + ent = next;
1803 + continue;
1804 + }
1805 + ent->next = sb->ent;
1806 + sb->ent = suspect->suspects;
1807 + suspect->suspects = NULL;
1808 + break;
1809 + }
1810 + }
1811 origin_decref(suspect);
1812
1813 if (DEBUG) /* sanity */
@@ -1602,9 +1864,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent,
1864 char hex[41];
1865
1866 strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
1605 - printf("%s%c%d %d %d\n",
1867 + printf("%s %d %d %d\n",
1868 hex,
1607 - ent->guilty ? ' ' : '*', /* purely for debugging */
1869 ent->s_lno + 1,
1870 ent->lno + 1,
1871 ent->num_lines);
@@ -1717,17 +1978,16 @@ static void output(struct scoreboard *sb, int option)
1978
1979 if (option & OUTPUT_PORCELAIN) {
1980 for (ent = sb->ent; ent; ent = ent->next) {
1720 - struct blame_entry *oth;
1721 - struct origin *suspect = ent->suspect;
1722 - struct commit *commit = suspect->commit;
1981 + int count = 0;
1982 + struct origin *suspect;
1983 + struct commit *commit = ent->suspect->commit;
1984 if (commit->object.flags & MORE_THAN_ONE_PATH)
1985 continue;
1725 - for (oth = ent->next; oth; oth = oth->next) {
1726 - if ((oth->suspect->commit != commit) ||
1727 - !strcmp(oth->suspect->path, suspect->path))
1728 - continue;
1729 - commit->object.flags |= MORE_THAN_ONE_PATH;
1730 - break;
1986 + for (suspect = commit->util; suspect; suspect = suspect->next) {
1987 + if (suspect->guilty && count++) {
1988 + commit->object.flags |= MORE_THAN_ONE_PATH;
1989 + break;
1990 + }
1991 }
1992 }
1993 }
@@ -2092,7 +2352,6 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
2352 origin->file.ptr = buf.buf;
2353 origin->file.size = buf.len;
2354 pretend_sha1_file(buf.buf, buf.len, OBJ_BLOB, origin->blob_sha1);
2095 - commit->util = origin;
2355
2356 /*
2357 * Read the current index, replace the path entry with
@@ -2403,12 +2662,16 @@ parse_done:
2662 memset(&sb, 0, sizeof(sb));
2663
2664 sb.revs = &revs;
2406 - if (!reverse)
2665 + if (!reverse) {
2666 final_commit_name = prepare_final(&sb);
2667 + sb.commits.compare = compare_commits_by_commit_date;
2668 + }
2669 else if (contents_from)
2670 die("--contents and --children do not blend well.");
2410 - else
2671 + else {
2672 final_commit_name = prepare_initial(&sb);
2673 + sb.commits.compare = compare_commits_by_reverse_commit_date;
2674 + }
2675
2676 if (!sb.final) {
2677 /*
@@ -2497,12 +2760,16 @@ parse_done:
2760 ent->next = next;
2761 origin_incref(o);
2762 }
2763 +
2764 + o->suspects = ent;
2765 + prio_queue_put(&sb.commits, o->commit);
2766 +
2767 origin_decref(o);
2768
2769 range_set_release(&ranges);
2770 string_list_clear(&range_list, 0);
2771
2505 - sb.ent = ent;
2772 + sb.ent = NULL;
2773 sb.path = path;
2774
2775 read_mailmap(&mailmap, NULL);
@@ -2515,6 +2782,8 @@ parse_done:
2782 if (incremental)
2783 return 0;
2784
2785 + sb.ent = blame_sort(sb.ent, compare_blame_final);
2786 +
2787 coalesce(&sb);
2788
2789 if (!(output_option & OUTPUT_PORCELAIN))