diffcore-rename: use a mem_pool for exact rename detection's hashmap

Exact rename detection, via insert_file_table(), uses a hashmap to store files by oid. Use a mem_pool for the hashmap entries so these can all be allocated and deallocated together. For the testcases mentioned in commit 557ac0350d ("merge-ort: begin performance work; instrument with trace2_region_* calls", 2020-10-28), this change improves the performance as follows: Before After no-renames: 204.2 ms ± 3.0 ms 202.5 ms ± 3.2 ms mega-renames: 1.076 s ± 0.015 s 1.072 s ± 0.012 s just-one-mega: 364.1 ms ± 7.0 ms 357.3 ms ± 3.9 ms Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Jul 30, 2021 at 11:47 UTC fa0e936fbb683dbce70b797ae8a5be6b88f48d88
1 file changed +16 -6
diffcore-rename.c
+16 -6
@@ -317,10 +317,11 @@ static int find_identical_files(struct hashmap *srcs,
317 }
318
319 static void insert_file_table(struct repository *r,
320 + struct mem_pool *pool,
321 struct hashmap *table, int index,
322 struct diff_filespec *filespec)
323 {
323 - struct file_similarity *entry = xmalloc(sizeof(*entry));
324 + struct file_similarity *entry = mem_pool_alloc(pool, sizeof(*entry));
325
326 entry->index = index;
327 entry->filespec = filespec;
@@ -336,7 +337,8 @@ static void insert_file_table(struct repository *r,
337 * and then during the second round we try to match
338 * cache-dirty entries as well.
339 */
339 -static int find_exact_renames(struct diff_options *options)
340 +static int find_exact_renames(struct diff_options *options,
341 + struct mem_pool *pool)
342 {
343 int i, renames = 0;
344 struct hashmap file_table;
@@ -346,7 +348,7 @@ static int find_exact_renames(struct diff_options *options)
348 */
349 hashmap_init(&file_table, NULL, NULL, rename_src_nr);
350 for (i = rename_src_nr-1; i >= 0; i--)
349 - insert_file_table(options->repo,
351 + insert_file_table(options->repo, pool,
352 &file_table, i,
353 rename_src[i].p->one);
354
@@ -354,8 +356,8 @@ static int find_exact_renames(struct diff_options *options)
356 for (i = 0; i < rename_dst_nr; i++)
357 renames += find_identical_files(&file_table, i, options);
358
357 - /* Free the hash data structure and entries */
358 - hashmap_clear_and_free(&file_table, struct file_similarity, entry);
359 + /* Free the hash data structure (entries will be freed with the pool) */
360 + hashmap_clear(&file_table);
361
362 return renames;
363 }
@@ -1341,6 +1343,7 @@ void diffcore_rename_extended(struct diff_options *options,
1343 int num_destinations, dst_cnt;
1344 int num_sources, want_copies;
1345 struct progress *progress = NULL;
1346 + struct mem_pool local_pool;
1347 struct dir_rename_info info;
1348 struct diff_populate_filespec_options dpf_options = {
1349 .check_binary = 0,
@@ -1409,11 +1412,18 @@ void diffcore_rename_extended(struct diff_options *options,
1412 goto cleanup; /* nothing to do */
1413
1414 trace2_region_enter("diff", "exact renames", options->repo);
1415 + mem_pool_init(&local_pool, 32*1024);
1416 /*
1417 * We really want to cull the candidates list early
1418 * with cheap tests in order to avoid doing deltas.
1419 */
1416 - rename_count = find_exact_renames(options);
1420 + rename_count = find_exact_renames(options, &local_pool);
1421 + /*
1422 + * Discard local_pool immediately instead of at "cleanup:" in order
1423 + * to reduce maximum memory usage; inexact rename detection uses up
1424 + * a fair amount of memory, and mem_pools can too.
1425 + */
1426 + mem_pool_discard(&local_pool, 0);
1427 trace2_region_leave("diff", "exact renames", options->repo);
1428
1429 /* Did we only want exact renames? */