From: Taylor Blau Date: Thu, 23 Oct 2025 23:56:56 GMT Subject: Re: [PATCH] last-modified: implement faster algorithm Message-ID: In-Reply-To: <87jz0tu3yh.fsf@iotcl.com> On Fri, Oct 17, 2025 at 02:07:18PM +0200, Toon Claes wrote: > > 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. > > 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. > > 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 ;-). > > 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