Re: [PATCH] last-modified: implement faster algorithm
- From
Taylor Blau <me@ttaylorr.com>
- Date
- Oct 23, 2025, 23:56 UTC
- Message-ID
- <aPrAyJYvWtlvmiEx@nand.local>
- In-Reply-To
- <87jz0tu3yh.fsf@iotcl.com>
On Fri, Oct 17, 2025 at 02:07:18PM +0200, Toon Claes wrote:
Show 6 quoted lines
> > Regardless of how you handle the above, I think that the commit slab > > name here is a little generic. I guess it's OK since this is only > > visible within this compilation unit, but perhaps something like > > "active_paths_bitmap" would be more descriptive. > > I struggled a lot naming this thing, so I'm open to suggestions.
I think calling it "active_paths_bitmap" or similar conveys that this is somehow specific to "active paths", and since the slab is static within the last-modified builtin, I think that's fine. It's a little word-y, so if you have better ideas with fewer characters, I'm open to just about anything.
Show 27 quoted lines
> > Likewise, I wonder if we should have elemtype here be just 'struct
> > bitmap'. Unfortunately I don't think the EWAH code has a function like:
> >
> > void bitmap_init(struct bitmap *);
> >
> > and only has ones that allocate for us. So we may consider adding one,
> > or creating a dummy bitmap and copying its contents, or otherwise.
> >
> >> struct last_modified {
> >> struct hashmap paths;
> >> struct rev_info rev;
> >> bool recursive;
> >> bool show_trees;
> >> +
> >> + const char **all_paths;
> >> + size_t all_paths_nr;
> >
> > I wonder if all_paths should be a strvec here? I think that this code
> > was all written when the type was called argv_array (hilariously, that
> > change took place towards the end of July, 2020, and the --go-faster
> > code where this patch came from was written just a couple of weeks
> > earlier.)
>
> Ahha, that might be a good idea. This might allow us to get rid of the
> hashmap, which stops us from storing the paths twice. Not sure what the
> impact on the performance would be, because the hashmap now is valuable
> for path_idx() lookups.Looking at this a little further, I don't think I consider this worth doing. Using a strvec here is awkward since last_modified_init() really wants to assign lm->all_paths based on each entry's diff_idx, which is not what strvec.h is designed for.
You *could* use a string_list, and shove a pointer to the last_modified_entry struct in the ->util field, but that is also inefficient since we remove paths from our hashmap as we mark them, and repeating that in a string_list would be wasteful.
Show 11 quoted lines
> > In the GitHub version of this patch, we pass all active paths to the > > parent, assign the PARENT1 flag if it doesn't already have it, and put > > it in the queue as well. > > > > In your version, we'd skip past the next for-loop, and do the same > > pass-to-parent dance below, along with inserting the parent into the > > prio queue. > > This is the "shortcut" I'm mentioning in my cover letter. In my testing > it seemed it didn't provide any performance gains to keep it. I consider > less code better code, so I left it out.
Fair enough. I don't think that less code here results in a lack of clarity, so this seems alright to me. But in general I am not sure that I always agree that less code is better ;-).
Show 28 quoted lines
> > So I think that this is all functionally equivalent, but I had to work
> > through a little bit of the details here, mostly since I haven't looked
> > at or thought about this code in many years ;-).
> >
> >> static int last_modified_run(struct last_modified *lm)
> >> {
> >> + int max_count, queue_popped = 0;
> >> + struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
> >> + struct prio_queue not_queue = { compare_commits_by_gen_then_commit_date };
> >> + struct commit_list *list;
> >> struct last_modified_callback_data data = { .lm = lm };
> >>
> >> lm->rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
> >> lm->rev.diffopt.format_callback = last_modified_diff;
> >> lm->rev.diffopt.format_callback_data = &data;
> >> + lm->rev.no_walk = 1;
> >
> > This one is new relative to the original patch. Why set no_walk here?
>
> This comes from
> https://github.com/ttaylorr/git/commit/e8ea49705873d28f64b815bd00d14bdf6d48ca4d
>
> Well, it basically squashes various commits together. There are various
> commits doing different things here. I don't think it's valuable for
> anyone to see the full history of the iterations at GitHub, that's why I
> squashed it in.
>
> Would you consider it better to not set `no_walk`?Hah, I forgot that we added this one later on. Adding it here in this patch makes sense to me.
Thanks, Taylor