Git fork

Merge branch 'pc/range-diff-memory-limit'

"git range-diff" learned a way to limit the memory consumed by
O(N*N) cost matrix.

* pc/range-diff-memory-limit:
range-diff: add configurable memory limit for cost matrix

+44 -4
+1
builtin/log.c
··· 1404 1404 struct range_diff_options range_diff_opts = { 1405 1405 .creation_factor = rev->creation_factor, 1406 1406 .dual_color = 1, 1407 + .max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT, 1407 1408 .diffopt = &opts, 1408 1409 .other_arg = &other_arg 1409 1410 };
+21
builtin/range-diff.c
··· 6 6 #include "parse-options.h" 7 7 #include "range-diff.h" 8 8 #include "config.h" 9 + #include "parse.h" 9 10 10 11 11 12 static const char * const builtin_range_diff_usage[] = { ··· 15 16 NULL 16 17 }; 17 18 19 + static int parse_max_memory(const struct option *opt, const char *arg, int unset) 20 + { 21 + size_t *max_memory = opt->value; 22 + uintmax_t val; 23 + 24 + if (unset) 25 + return 0; 26 + 27 + if (!git_parse_unsigned(arg, &val, SIZE_MAX)) 28 + return error(_("invalid max-memory value: %s"), arg); 29 + 30 + *max_memory = (size_t)val; 31 + return 0; 32 + } 33 + 18 34 int cmd_range_diff(int argc, 19 35 const char **argv, 20 36 const char *prefix, ··· 25 41 struct strvec diff_merges_arg = STRVEC_INIT; 26 42 struct range_diff_options range_diff_opts = { 27 43 .creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT, 44 + .max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT, 28 45 .diffopt = &diffopt, 29 46 .other_arg = &other_arg 30 47 }; ··· 40 57 PARSE_OPT_OPTARG), 41 58 OPT_PASSTHRU_ARGV(0, "diff-merges", &diff_merges_arg, 42 59 N_("style"), N_("passed to 'git log'"), 0), 60 + OPT_CALLBACK(0, "max-memory", &range_diff_opts.max_memory, 61 + N_("size"), 62 + N_("maximum memory for cost matrix (default 4G)"), 63 + parse_max_memory), 43 64 OPT_PASSTHRU_ARGV(0, "remerge-diff", &diff_merges_arg, NULL, 44 65 N_("passed to 'git log'"), PARSE_OPT_NOARG), 45 66 OPT_BOOL(0, "left-only", &left_only,
+1
log-tree.c
··· 717 717 struct range_diff_options range_diff_opts = { 718 718 .creation_factor = opt->creation_factor, 719 719 .dual_color = 1, 720 + .max_memory = RANGE_DIFF_MAX_MEMORY_DEFAULT, 720 721 .diffopt = &opts 721 722 }; 722 723
+16 -4
range-diff.c
··· 325 325 } 326 326 327 327 static void get_correspondences(struct string_list *a, struct string_list *b, 328 - int creation_factor) 328 + int creation_factor, size_t max_memory) 329 329 { 330 330 int n = a->nr + b->nr; 331 331 int *cost, c, *a2b, *b2a; 332 332 int i, j; 333 - 334 - ALLOC_ARRAY(cost, st_mult(n, n)); 333 + size_t cost_size = st_mult(n, n); 334 + size_t cost_bytes = st_mult(sizeof(int), cost_size); 335 + if (cost_bytes >= max_memory) { 336 + struct strbuf cost_str = STRBUF_INIT; 337 + struct strbuf max_str = STRBUF_INIT; 338 + strbuf_humanise_bytes(&cost_str, cost_bytes); 339 + strbuf_humanise_bytes(&max_str, max_memory); 340 + die(_("range-diff: unable to compute the range-diff, since it " 341 + "exceeds the maximum memory for the cost matrix: %s " 342 + "(%"PRIuMAX" bytes) needed, limited to %s (%"PRIuMAX" bytes)"), 343 + cost_str.buf, (uintmax_t)cost_bytes, max_str.buf, (uintmax_t)max_memory); 344 + } 345 + ALLOC_ARRAY(cost, cost_size); 335 346 ALLOC_ARRAY(a2b, n); 336 347 ALLOC_ARRAY(b2a, n); 337 348 ··· 591 602 if (!res) { 592 603 find_exact_matches(&branch1, &branch2); 593 604 get_correspondences(&branch1, &branch2, 594 - range_diff_opts->creation_factor); 605 + range_diff_opts->creation_factor, 606 + range_diff_opts->max_memory); 595 607 output(&branch1, &branch2, range_diff_opts); 596 608 } 597 609
+5
range-diff.h
··· 5 5 #include "strvec.h" 6 6 7 7 #define RANGE_DIFF_CREATION_FACTOR_DEFAULT 60 8 + #define RANGE_DIFF_MAX_MEMORY_DEFAULT \ 9 + (sizeof(void*) >= 8 ? \ 10 + ((size_t)(1024L * 1024L) * (size_t)(4L * 1024L)) : /* 4GB on 64-bit */ \ 11 + ((size_t)(1024L * 1024L) * (size_t)(2L * 1024L))) /* 2GB on 32-bit */ 8 12 9 13 /* 10 14 * A much higher value than the default, when we KNOW we are comparing ··· 17 21 unsigned dual_color:1; 18 22 unsigned left_only:1, right_only:1; 19 23 unsigned include_merges:1; 24 + size_t max_memory; 20 25 const struct diff_options *diffopt; /* may be NULL */ 21 26 const struct strvec *other_arg; /* may be NULL */ 22 27 };