google / jsonnet

Jsonnet - The data templating language
http://jsonnet.org
Apache License 2.0
6.87k stars 436 forks source link

Improve performance of escapeStringBash and escapeStringDollars #1149

Closed itchyny closed 3 months ago

itchyny commented 3 months ago

This PR improves the performance of escapeStringBash and escapeStringDollars. The std.strReplace function is fast when the second string has length 1.

 $ hyperfine --warmup 10 "jsonnet -e \"std.escapeStringDollars('$str')\"" "./jsonnet -e \"std.escapeStringDollars('$str')\""
Benchmark 1: jsonnet -e "std.escapeStringDollars('1e+06$1e+06$1e+06$1e+06$1e+06$1.00000e+06$1.00001e+06$1.00001e+06$1.00001e+06$1.00001e+06$1.00001e+06$1.00001e+06')"

 $ str=$(seq 100000 100010 | paste -s -d $ -)
 $ hyperfine --warmup 10 "jsonnet -e \"std.escapeStringDollars('$str')\"" "./jsonnet -e \"std.escapeStringDollars('$str')\""
Benchmark 1: jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010')"
  Time (mean ± σ):      48.0 ms ±   0.6 ms    [User: 44.2 ms, System: 2.9 ms]
  Range (min … max):    47.4 ms …  50.8 ms    58 runs

  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Benchmark 2: ./jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010')"
  Time (mean ± σ):      45.6 ms ±   0.4 ms    [User: 41.9 ms, System: 2.7 ms]
  Range (min … max):    45.1 ms …  46.9 ms    61 runs

Summary
  ./jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010')" ran
    1.05 ± 0.02 times faster than jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010')"

 $ str=$(seq 100000 100100 | paste -s -d $ -)
 $ hyperfine --warmup 10 "jsonnet -e \"std.escapeStringDollars('$str')\"" "./jsonnet -e \"std.escapeStringDollars('$str')\""
Benchmark 1: jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010$100011$100012$100013$100014$ ...(abbr.)
  Time (mean ± σ):      61.1 ms ±   1.2 ms    [User: 57.0 ms, System: 3.1 ms]
  Range (min … max):    60.0 ms …  66.9 ms    46 runs

  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Benchmark 2: ./jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010$100011$100012$100013$100014$ ...(abbr.)
  Time (mean ± σ):      46.3 ms ±   2.1 ms    [User: 42.3 ms, System: 2.9 ms]
  Range (min … max):    45.1 ms …  57.2 ms    60 runs

  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Summary
  ./jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010$100011$100012$100013$100014$ ...(abbr.)
    1.32 ± 0.07 times faster than jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010$100011$100012$100013$100014$ ...(abbr.)

 $ str=$(seq 100000 101000 | paste -s -d $ -)
 $ hyperfine --warmup 10 "jsonnet -e \"std.escapeStringDollars('$str')\"" "./jsonnet -e \"std.escapeStringDollars('$str')\""
Benchmark 1: jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010$100011$100012$100013$100014$ ...(abbr.)
  Time (mean ± σ):     197.9 ms ±   5.0 ms    [User: 190.5 ms, System: 5.6 ms]
  Range (min … max):   192.8 ms … 211.6 ms    13 runs

Benchmark 2: ./jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010$100011$100012$100013$100014$ ...(abbr.)
  Time (mean ± σ):      47.0 ms ±   1.5 ms    [User: 43.0 ms, System: 2.9 ms]
  Range (min … max):    45.9 ms …  55.0 ms    60 runs

  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.

Summary
  ./jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010$100011$100012$100013$100014$ ...(abbr.)
    4.21 ± 0.17 times faster than jsonnet -e "std.escapeStringDollars('100000$100001$100002$100003$100004$100005$100006$100007$100008$100009$100010$100011$100012$100013$100014$ ...(abbr.)
johnbartholomew commented 3 months ago

Hi. Thanks for the contribution!

I agree this seems like an improvement - also just in terms of making the code a little simpler. std.strReplace is implemented as a builtin in C++ jsonnet, so it does make some sense that this would be faster too.