cat-file: skip expanding default format

When format is passed into --batch, --batch-check, --batch-command, the format gets expanded. When nothing is passed in, the default format is set and the expand_format() gets called. We can save on these cycles by hardcoding how to print the information when nothing is passed as the format, or when the default format is passed. There is no need for the fully expanded format with the default. Since batch_object_write() happens on every object provided in batch mode, we get a nice performance improvement. git rev-list --all > /tmp/all-obj.txt git cat-file --batch-check </tmp/all-obj.txt with HEAD^: Time (mean ± σ): 57.6 ms ± 1.7 ms [User: 51.5 ms, System: 6.2 ms] Range (min … max): 54.6 ms … 64.7 ms 50 runs with HEAD: Time (mean ± σ): 49.8 ms ± 1.7 ms [User: 42.6 ms, System: 7.3 ms] Range (min … max): 46.9 ms … 55.9 ms 56 runs If nothing is provided as a format argument, or if the default format is passed, skip expanding of the format and print the object info with a default format. See https://lore.kernel.org/git/87eecf8ork.fsf@evledraar.gmail.com/ Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: John Cai <johncai86@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

John Cai committed Mar 15, 2022 at 02:40 UTC eb54a3391bb3bdd6806ebffc21281eae8d9c0dca
2 files changed +35 -6
builtin/cat-file.c
+23 -6
@@ -351,6 +351,13 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
351 }
352 }
353
354 +static void print_default_format(struct strbuf *scratch, struct expand_data *data)
355 +{
356 + strbuf_addf(scratch, "%s %s %"PRIuMAX"\n", oid_to_hex(&data->oid),
357 + type_name(data->type),
358 + (uintmax_t)data->size);
359 +}
360 +
361 /*
362 * If "pack" is non-NULL, then "offset" is the byte offset within the pack from
363 * which the object may be accessed (though note that we may also rely on
@@ -382,8 +389,14 @@ static void batch_object_write(const char *obj_name,
389 }
390
391 strbuf_reset(scratch);
385 - strbuf_expand(scratch, opt->format, expand_format, data);
386 - strbuf_addch(scratch, '\n');
392 +
393 + if (!opt->format) {
394 + print_default_format(scratch, data);
395 + } else {
396 + strbuf_expand(scratch, opt->format, expand_format, data);
397 + strbuf_addch(scratch, '\n');
398 + }
399 +
400 batch_write(opt, scratch->buf, scratch->len);
401
402 if (opt->print_contents) {
@@ -508,6 +521,8 @@ static int batch_unordered_packed(const struct object_id *oid,
521 data);
522 }
523
524 +#define DEFAULT_FORMAT "%(objectname) %(objecttype) %(objectsize)"
525 +
526 static int batch_objects(struct batch_options *opt)
527 {
528 struct strbuf input = STRBUF_INIT;
@@ -516,9 +531,6 @@ static int batch_objects(struct batch_options *opt)
531 int save_warning;
532 int retval = 0;
533
519 - if (!opt->format)
520 - opt->format = "%(objectname) %(objecttype) %(objectsize)";
521 -
534 /*
535 * Expand once with our special mark_query flag, which will prime the
536 * object_info to be handed to oid_object_info_extended for each
@@ -526,12 +538,17 @@ static int batch_objects(struct batch_options *opt)
538 */
539 memset(&data, 0, sizeof(data));
540 data.mark_query = 1;
529 - strbuf_expand(&output, opt->format, expand_format, &data);
541 + strbuf_expand(&output,
542 + opt->format ? opt->format : DEFAULT_FORMAT,
543 + expand_format,
544 + &data);
545 data.mark_query = 0;
546 strbuf_release(&output);
547 if (opt->cmdmode)
548 data.split_on_whitespace = 1;
549
550 + if (opt->format && !strcmp(opt->format, DEFAULT_FORMAT))
551 + opt->format = NULL;
552 /*
553 * If we are printing out the object, then always fill in the type,
554 * since we will want to decide whether or not to stream.
t/perf/p1006-cat-file.sh new
+12
@@ -0,0 +1,12 @@
1 +#!/bin/sh
2 +
3 +test_description='Tests listing object info performance'
4 +. ./perf-lib.sh
5 +
6 +test_perf_large_repo
7 +
8 +test_perf 'cat-file --batch-check' '
9 + git cat-file --batch-all-objects --batch-check
10 +'
11 +
12 +test_done