diff --git a/crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.json b/crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.json new file mode 100644 index 000000000..07a9e021e --- /dev/null +++ b/crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.json @@ -0,0 +1,4842 @@ +{ + "moniker": "mykhailosmin-macos-aarch64", + "timestamp": "1791865783", + "system": { + "hostname": "Mykhailos-Mini.lan", + "os": "macos", + "arch": "aarch64", + "cpus": 12, + "moniker": "mykhailosmin-macos-aarch64" + }, + "iterations": 10, + "warmup": 2, + "prewarm_cases": 3, + "runners": [ + "bashkit", + "bash" + ], + "runner_versions": { + "bash": "/opt/homebrew/bin/bash (GNU Bash 5.3.20(1)-release)" + }, + "results": [ + { + "runner": "bashkit", + "case_name": "startup_empty", + "category": "startup", + "iterations": 10, + "times_ns": [ + 33209, + 31208, + 30375, + 29417, + 29375, + 28875, + 29167, + 28750, + 28750, + 28084 + ], + "mean_ns": 29721.0, + "stddev_ns": 1435.452681212446, + "min_ns": 28084, + "max_ns": 33209, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "startup_empty", + "category": "startup", + "iterations": 10, + "times_ns": [ + 4700208, + 4445375, + 5277542, + 4622792, + 4674833, + 4430459, + 4760916, + 4545000, + 4516916, + 4603708 + ], + "mean_ns": 4657774.9, + "stddev_ns": 230289.7236445647, + "min_ns": 4430459, + "max_ns": 5277542, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "startup_true", + "category": "startup", + "iterations": 10, + "times_ns": [ + 33167, + 31750, + 30167, + 29625, + 29500, + 29292, + 29166, + 29375, + 29167, + 28917 + ], + "mean_ns": 30012.6, + "stddev_ns": 1302.4414919680653, + "min_ns": 28917, + "max_ns": 33167, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "startup_true", + "category": "startup", + "iterations": 10, + "times_ns": [ + 4795791, + 5318792, + 6657625, + 5103084, + 4400542, + 4860375, + 5268292, + 4907416, + 4925584, + 4717958 + ], + "mean_ns": 5095545.9, + "stddev_ns": 579212.3337850205, + "min_ns": 4400542, + "max_ns": 6657625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "startup_echo", + "category": "startup", + "iterations": 10, + "times_ns": [ + 35208, + 35750, + 31958, + 31333, + 30541, + 29833, + 31625, + 30041, + 29917, + 29750 + ], + "mean_ns": 31595.6, + "stddev_ns": 2082.5294331653513, + "min_ns": 29750, + "max_ns": 35750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "startup_echo", + "category": "startup", + "iterations": 10, + "times_ns": [ + 4729750, + 4929917, + 4734833, + 5001750, + 4690375, + 5007000, + 4970542, + 4949042, + 4702167, + 4776042 + ], + "mean_ns": 4849141.8, + "stddev_ns": 126065.11750345533, + "min_ns": 4690375, + "max_ns": 5007000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "startup_exit", + "category": "startup", + "iterations": 10, + "times_ns": [ + 34750, + 30916, + 34083, + 30333, + 29208, + 30416, + 31459, + 31250, + 29792, + 29542 + ], + "mean_ns": 31174.9, + "stddev_ns": 1764.1984837313516, + "min_ns": 29208, + "max_ns": 34750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "startup_exit", + "category": "startup", + "iterations": 10, + "times_ns": [ + 5013459, + 4757958, + 4569709, + 4660667, + 4817209, + 4239667, + 4355583, + 5037625, + 4675625, + 5065167 + ], + "mean_ns": 4719266.9, + "stddev_ns": 266200.22149819863, + "min_ns": 4239667, + "max_ns": 5065167, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "var_assign_simple", + "category": "variables", + "iterations": 10, + "times_ns": [ + 37250, + 34458, + 33333, + 33583, + 35625, + 39250, + 35333, + 34833, + 35000, + 34000 + ], + "mean_ns": 35266.5, + "stddev_ns": 1703.6643595497324, + "min_ns": 33333, + "max_ns": 39250, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "var_assign_simple", + "category": "variables", + "iterations": 10, + "times_ns": [ + 5368750, + 4941417, + 4941084, + 5003542, + 4947375, + 4576292, + 4751708, + 4507833, + 4931125, + 5101417 + ], + "mean_ns": 4907054.3, + "stddev_ns": 236158.3041690679, + "min_ns": 4507833, + "max_ns": 5368750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "var_assign_many", + "category": "variables", + "iterations": 10, + "times_ns": [ + 49292, + 46792, + 49167, + 45291, + 44292, + 44375, + 43667, + 44500, + 44125, + 42833 + ], + "mean_ns": 45433.4, + "stddev_ns": 2135.01836994439, + "min_ns": 42833, + "max_ns": 49292, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "var_assign_many", + "category": "variables", + "iterations": 10, + "times_ns": [ + 4342125, + 4493459, + 4045917, + 4157125, + 4264666, + 4329083, + 4148792, + 4159292, + 4064083, + 4077875 + ], + "mean_ns": 4208241.7, + "stddev_ns": 137742.41907201282, + "min_ns": 4045917, + "max_ns": 4493459, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "var_default", + "category": "variables", + "iterations": 10, + "times_ns": [ + 35375, + 32792, + 31584, + 30709, + 30833, + 30417, + 30875, + 30125, + 30084, + 30208 + ], + "mean_ns": 31300.2, + "stddev_ns": 1564.9847794787015, + "min_ns": 30084, + "max_ns": 35375, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "var_default", + "category": "variables", + "iterations": 10, + "times_ns": [ + 4073084, + 4105458, + 4183375, + 4101000, + 4093167, + 4118959, + 4162166, + 4201667, + 4003625, + 4680458 + ], + "mean_ns": 4172295.9, + "stddev_ns": 177838.75682226865, + "min_ns": 4003625, + "max_ns": 4680458, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "var_length", + "category": "variables", + "iterations": 10, + "times_ns": [ + 36125, + 32667, + 31709, + 31042, + 31291, + 30583, + 30500, + 30250, + 30333, + 30167 + ], + "mean_ns": 31466.7, + "stddev_ns": 1719.904593284174, + "min_ns": 30167, + "max_ns": 36125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "var_length", + "category": "variables", + "iterations": 10, + "times_ns": [ + 4394334, + 4668583, + 4713250, + 5428584, + 4589209, + 5080458, + 4500292, + 4534458, + 4151666, + 4233541 + ], + "mean_ns": 4629437.5, + "stddev_ns": 363070.62999484, + "min_ns": 4151666, + "max_ns": 5428584, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "var_substring", + "category": "variables", + "iterations": 10, + "times_ns": [ + 37625, + 34083, + 49000, + 33416, + 32500, + 32125, + 32333, + 31750, + 31834, + 31958 + ], + "mean_ns": 34662.4, + "stddev_ns": 5065.265702803754, + "min_ns": 31750, + "max_ns": 49000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "var_substring", + "category": "variables", + "iterations": 10, + "times_ns": [ + 4404542, + 4152666, + 3994958, + 4456583, + 4395792, + 4178583, + 4367209, + 4490167, + 4312834, + 4460000 + ], + "mean_ns": 4321333.4, + "stddev_ns": 153628.61051783292, + "min_ns": 3994958, + "max_ns": 4490167, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "var_replace", + "category": "variables", + "iterations": 10, + "times_ns": [ + 37959, + 42292, + 34917, + 34833, + 34458, + 34042, + 33833, + 33625, + 33334, + 33042 + ], + "mean_ns": 35233.5, + "stddev_ns": 2692.4312897453856, + "min_ns": 33042, + "max_ns": 42292, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "var_replace", + "category": "variables", + "iterations": 10, + "times_ns": [ + 4294792, + 4644125, + 4275584, + 4379250, + 4480791, + 4303292, + 4385958, + 4104584, + 4697167, + 4118000 + ], + "mean_ns": 4368354.3, + "stddev_ns": 186478.089547834, + "min_ns": 4104584, + "max_ns": 4697167, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "var_nested", + "category": "variables", + "iterations": 10, + "times_ns": [ + 38458, + 35000, + 34250, + 34125, + 33583, + 32792, + 33000, + 33208, + 32833, + 32792 + ], + "mean_ns": 34004.1, + "stddev_ns": 1644.1803702757188, + "min_ns": 32792, + "max_ns": 38458, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "var_nested", + "category": "variables", + "iterations": 10, + "times_ns": [ + 4531417, + 5385625, + 4843666, + 4940250, + 4396583, + 4867584, + 4419000, + 5767875, + 4680666, + 4621083 + ], + "mean_ns": 4845374.9, + "stddev_ns": 413713.57484193094, + "min_ns": 4396583, + "max_ns": 5767875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "var_export", + "category": "variables", + "iterations": 10, + "times_ns": [ + 41750, + 37583, + 35250, + 34750, + 34708, + 34000, + 34000, + 33416, + 33500, + 38208 + ], + "mean_ns": 35716.5, + "stddev_ns": 2536.9519211053253, + "min_ns": 33416, + "max_ns": 41750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "var_export", + "category": "variables", + "iterations": 10, + "times_ns": [ + 4864292, + 5052958, + 4716000, + 4637625, + 4297375, + 4909459, + 4871625, + 5024458, + 4792041, + 4740334 + ], + "mean_ns": 4790616.7, + "stddev_ns": 206012.24803299925, + "min_ns": 4297375, + "max_ns": 5052958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arith_basic", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 36458, + 33667, + 33000, + 32292, + 32125, + 31958, + 33541, + 32250, + 31416, + 31250 + ], + "mean_ns": 32795.7, + "stddev_ns": 1440.994729344976, + "min_ns": 31250, + "max_ns": 36458, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arith_basic", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 4702000, + 4591959, + 4597625, + 5220333, + 5328583, + 5165042, + 5122166, + 5034584, + 4836750, + 5141792 + ], + "mean_ns": 4974083.4, + "stddev_ns": 256343.28461428435, + "min_ns": 4591959, + "max_ns": 5328583, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arith_complex", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 35750, + 33167, + 32292, + 31291, + 31208, + 30917, + 30791, + 30875, + 30708, + 30709 + ], + "mean_ns": 31770.8, + "stddev_ns": 1528.0841468976766, + "min_ns": 30708, + "max_ns": 35750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arith_complex", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 4659416, + 4506459, + 5027584, + 4345667, + 4877333, + 4966959, + 5338667, + 5208041, + 4688042, + 4574792 + ], + "mean_ns": 4819296.0, + "stddev_ns": 302355.4708765826, + "min_ns": 4345667, + "max_ns": 5338667, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arith_variables", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 40792, + 38000, + 36750, + 36209, + 34959, + 35125, + 34834, + 34959, + 35000, + 34417 + ], + "mean_ns": 36104.5, + "stddev_ns": 1877.7293335302616, + "min_ns": 34417, + "max_ns": 40792, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arith_variables", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 4668584, + 5574959, + 4817167, + 4802333, + 4417208, + 4431125, + 4356834, + 4507083, + 4315958, + 4395375 + ], + "mean_ns": 4628662.6, + "stddev_ns": 358800.7414778292, + "min_ns": 4315958, + "max_ns": 5574959, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arith_increment", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 38584, + 37791, + 37292, + 34875, + 34708, + 34417, + 34375, + 33625, + 33959, + 33459 + ], + "mean_ns": 35308.5, + "stddev_ns": 1763.9917375089942, + "min_ns": 33459, + "max_ns": 38584, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arith_increment", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 4349291, + 4245750, + 4282625, + 4354750, + 4052916, + 4825958, + 4464583, + 4680042, + 5274084, + 4868125 + ], + "mean_ns": 4539812.4, + "stddev_ns": 348479.5126721799, + "min_ns": 4052916, + "max_ns": 5274084, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arith_modulo", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 34667, + 32125, + 31250, + 31042, + 31166, + 31167, + 30209, + 30584, + 30250, + 30292 + ], + "mean_ns": 31275.2, + "stddev_ns": 1262.4331110993564, + "min_ns": 30209, + "max_ns": 34667, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arith_modulo", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 4651750, + 4818792, + 4977125, + 4694416, + 4703875, + 4864791, + 4823958, + 4726750, + 4411583, + 4830125 + ], + "mean_ns": 4750316.5, + "stddev_ns": 145368.72628130854, + "min_ns": 4411583, + "max_ns": 4977125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arith_loop_sum", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 59000, + 55000, + 56458, + 52708, + 54333, + 54625, + 52167, + 54209, + 52084, + 51250 + ], + "mean_ns": 54183.4, + "stddev_ns": 2202.573776289911, + "min_ns": 51250, + "max_ns": 59000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arith_loop_sum", + "category": "arithmetic", + "iterations": 10, + "times_ns": [ + 4714875, + 4511416, + 4986459, + 4445666, + 4995666, + 5281250, + 4641708, + 5303167, + 5156042, + 4927666 + ], + "mean_ns": 4896391.5, + "stddev_ns": 291396.28802105563, + "min_ns": 4445666, + "max_ns": 5303167, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_if_simple", + "category": "control", + "iterations": 10, + "times_ns": [ + 37667, + 34750, + 34000, + 33209, + 33042, + 33333, + 33125, + 33041, + 32542, + 32583 + ], + "mean_ns": 33729.2, + "stddev_ns": 1452.0108677279243, + "min_ns": 32542, + "max_ns": 37667, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_if_simple", + "category": "control", + "iterations": 10, + "times_ns": [ + 4800709, + 4637000, + 5300000, + 5186875, + 5058792, + 5293750, + 4925708, + 6250500, + 17283041, + 14019125 + ], + "mean_ns": 7275550.0, + "stddev_ns": 4270735.969708734, + "min_ns": 4637000, + "max_ns": 17283041, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_if_else", + "category": "control", + "iterations": 10, + "times_ns": [ + 41583, + 38625, + 37000, + 36292, + 35500, + 35750, + 34833, + 34708, + 34542, + 34375 + ], + "mean_ns": 36320.8, + "stddev_ns": 2150.03938568576, + "min_ns": 34375, + "max_ns": 41583, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_if_else", + "category": "control", + "iterations": 10, + "times_ns": [ + 9863583, + 28158750, + 16193291, + 17913458, + 11856917, + 11987542, + 11797958, + 8098291, + 8823125, + 12433417 + ], + "mean_ns": 13712633.2, + "stddev_ns": 5607639.400050824, + "min_ns": 8098291, + "max_ns": 28158750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_for_list", + "category": "control", + "iterations": 10, + "times_ns": [ + 122208, + 73083, + 52583, + 50125, + 47292, + 46292, + 45416, + 45333, + 77958, + 59125 + ], + "mean_ns": 61941.5, + "stddev_ns": 22926.63365280651, + "min_ns": 45333, + "max_ns": 122208, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_for_list", + "category": "control", + "iterations": 10, + "times_ns": [ + 19902875, + 12407500, + 19771875, + 8205541, + 11965500, + 16155125, + 11722458, + 12126583, + 7887500, + 16466750 + ], + "mean_ns": 13661170.7, + "stddev_ns": 4050313.4117537634, + "min_ns": 7887500, + "max_ns": 19902875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_for_range", + "category": "control", + "iterations": 10, + "times_ns": [ + 60875, + 56791, + 58875, + 53750, + 53000, + 52708, + 52792, + 52334, + 52375, + 52292 + ], + "mean_ns": 54579.2, + "stddev_ns": 2966.32226165668, + "min_ns": 52292, + "max_ns": 60875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_for_range", + "category": "control", + "iterations": 10, + "times_ns": [ + 10293916, + 5121250, + 5884250, + 6325417, + 7005625, + 7180125, + 11426084, + 10228417, + 5813916, + 9137167 + ], + "mean_ns": 7841616.7, + "stddev_ns": 2121697.630787575, + "min_ns": 5121250, + "max_ns": 11426084, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_while", + "category": "control", + "iterations": 10, + "times_ns": [ + 77833, + 73000, + 72083, + 70291, + 70375, + 70333, + 98125, + 93583, + 78375, + 73417 + ], + "mean_ns": 77741.5, + "stddev_ns": 9511.639072736096, + "min_ns": 70291, + "max_ns": 98125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_while", + "category": "control", + "iterations": 10, + "times_ns": [ + 9081750, + 11869292, + 8372125, + 14168083, + 11166083, + 9631250, + 13342167, + 12317208, + 13320125, + 12127292 + ], + "mean_ns": 11539537.5, + "stddev_ns": 1850471.074636037, + "min_ns": 8372125, + "max_ns": 14168083, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_case", + "category": "control", + "iterations": 10, + "times_ns": [ + 42416, + 37791, + 36167, + 37084, + 35875, + 35417, + 35750, + 34834, + 35500, + 35083 + ], + "mean_ns": 36591.7, + "stddev_ns": 2119.977643750047, + "min_ns": 34834, + "max_ns": 42416, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_case", + "category": "control", + "iterations": 10, + "times_ns": [ + 15821208, + 13369500, + 18686916, + 12206000, + 16067708, + 9937042, + 21144792, + 25980916, + 11929250, + 9800041 + ], + "mean_ns": 15494337.3, + "stddev_ns": 4938325.758069592, + "min_ns": 9800041, + "max_ns": 25980916, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_function", + "category": "control", + "iterations": 10, + "times_ns": [ + 49500, + 183417, + 56750, + 43250, + 39667, + 37042, + 36583, + 35583, + 35416, + 35083 + ], + "mean_ns": 55229.1, + "stddev_ns": 43261.75261925942, + "min_ns": 35083, + "max_ns": 183417, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_function", + "category": "control", + "iterations": 10, + "times_ns": [ + 9239666, + 10918666, + 8217917, + 6315250, + 7311042, + 11130500, + 5857208, + 6274708, + 6241958, + 6861833 + ], + "mean_ns": 7836874.8, + "stddev_ns": 1868265.8882957639, + "min_ns": 5857208, + "max_ns": 11130500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_function_return", + "category": "control", + "iterations": 10, + "times_ns": [ + 51792, + 47292, + 45542, + 44625, + 47250, + 44625, + 43542, + 43750, + 43500, + 43125 + ], + "mean_ns": 45504.3, + "stddev_ns": 2528.492556840933, + "min_ns": 43125, + "max_ns": 51792, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_function_return", + "category": "control", + "iterations": 10, + "times_ns": [ + 6862125, + 7372917, + 6343833, + 11210375, + 9711833, + 7758416, + 6910791, + 7017000, + 6279667, + 6672041 + ], + "mean_ns": 7613899.8, + "stddev_ns": 1520232.770460616, + "min_ns": 6279667, + "max_ns": 11210375, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "ctrl_nested_loops", + "category": "control", + "iterations": 10, + "times_ns": [ + 71667, + 71000, + 68417, + 64458, + 64167, + 63875, + 62709, + 61291, + 62250, + 62250 + ], + "mean_ns": 65208.4, + "stddev_ns": 3578.7443663944478, + "min_ns": 61291, + "max_ns": 71667, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "ctrl_nested_loops", + "category": "control", + "iterations": 10, + "times_ns": [ + 12594042, + 6953708, + 7825417, + 9080042, + 8982042, + 6128417, + 5434458, + 6104875, + 6242209, + 7887209 + ], + "mean_ns": 7723241.9, + "stddev_ns": 2009334.548499301, + "min_ns": 5434458, + "max_ns": 12594042, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "str_concat", + "category": "strings", + "iterations": 10, + "times_ns": [ + 139458, + 69875, + 64041, + 40792, + 37334, + 180041, + 39750, + 36208, + 35375, + 34291 + ], + "mean_ns": 67716.5, + "stddev_ns": 48340.43537091903, + "min_ns": 34291, + "max_ns": 180041, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "str_concat", + "category": "strings", + "iterations": 10, + "times_ns": [ + 10952667, + 5866458, + 7403375, + 6728791, + 7716167, + 10515292, + 7649250, + 6931583, + 6115041, + 6621458 + ], + "mean_ns": 7650008.2, + "stddev_ns": 1647497.463830327, + "min_ns": 5866458, + "max_ns": 10952667, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "str_printf", + "category": "strings", + "iterations": 10, + "times_ns": [ + 40083, + 36500, + 35667, + 34834, + 34792, + 35459, + 33542, + 32916, + 32500, + 32292 + ], + "mean_ns": 34858.5, + "stddev_ns": 2206.017690318915, + "min_ns": 32292, + "max_ns": 40083, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "str_printf", + "category": "strings", + "iterations": 10, + "times_ns": [ + 7572000, + 5724083, + 6793583, + 7698542, + 12455833, + 10098625, + 10260500, + 11026875, + 8367834, + 7402500 + ], + "mean_ns": 8740037.5, + "stddev_ns": 2011356.788642296, + "min_ns": 5724083, + "max_ns": 12455833, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "str_printf_pad", + "category": "strings", + "iterations": 10, + "times_ns": [ + 153833, + 183916, + 73875, + 43291, + 38708, + 89125, + 189542, + 77250, + 177334, + 93958 + ], + "mean_ns": 112083.2, + "stddev_ns": 55502.82560518879, + "min_ns": 38708, + "max_ns": 189542, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "str_printf_pad", + "category": "strings", + "iterations": 10, + "times_ns": [ + 8093834, + 12640000, + 8503500, + 7046292, + 6699208, + 7358042, + 5575334, + 6544292, + 10613334, + 6394291 + ], + "mean_ns": 7946812.7, + "stddev_ns": 2053856.4704499706, + "min_ns": 5575334, + "max_ns": 12640000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "str_echo_escape", + "category": "strings", + "iterations": 10, + "times_ns": [ + 35667, + 34042, + 33375, + 32500, + 31708, + 31042, + 31958, + 31000, + 30708, + 30667 + ], + "mean_ns": 32266.7, + "stddev_ns": 1565.1496446027134, + "min_ns": 30667, + "max_ns": 35667, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "str_echo_escape", + "category": "strings", + "iterations": 10, + "times_ns": [ + 10036417, + 7500792, + 13535042, + 9379041, + 17060833, + 9943208, + 8046083, + 8039584, + 7704542, + 9841958 + ], + "mean_ns": 10108750.0, + "stddev_ns": 2860505.697358843, + "min_ns": 7500792, + "max_ns": 17060833, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "str_prefix_strip", + "category": "strings", + "iterations": 10, + "times_ns": [ + 93459, + 83792, + 77292, + 228250, + 94958, + 82417, + 79292, + 82500, + 75458, + 94000 + ], + "mean_ns": 99141.8, + "stddev_ns": 43554.33309970433, + "min_ns": 75458, + "max_ns": 228250, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "str_prefix_strip", + "category": "strings", + "iterations": 10, + "times_ns": [ + 8701791, + 8159458, + 11312500, + 7082333, + 8074166, + 7021875, + 7358542, + 8273750, + 8756916, + 8286833 + ], + "mean_ns": 8302816.4, + "stddev_ns": 1162736.4384775425, + "min_ns": 7021875, + "max_ns": 11312500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "str_suffix_strip", + "category": "strings", + "iterations": 10, + "times_ns": [ + 40708, + 36958, + 35791, + 35083, + 34625, + 34292, + 34292, + 34125, + 517208, + 106458 + ], + "mean_ns": 90954.0, + "stddev_ns": 143652.79539361564, + "min_ns": 34125, + "max_ns": 517208, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "str_suffix_strip", + "category": "strings", + "iterations": 10, + "times_ns": [ + 8017916, + 6769416, + 7499333, + 5926500, + 6330959, + 5310792, + 9129042, + 9095000, + 10549875, + 19325000 + ], + "mean_ns": 8795383.3, + "stddev_ns": 3833890.5513870125, + "min_ns": 5310792, + "max_ns": 19325000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "str_uppercase", + "category": "strings", + "iterations": 10, + "times_ns": [ + 143208, + 88583, + 78083, + 165958, + 65208, + 42125, + 37958, + 36625, + 35958, + 34750 + ], + "mean_ns": 72845.6, + "stddev_ns": 44987.794960855776, + "min_ns": 34750, + "max_ns": 165958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "str_uppercase", + "category": "strings", + "iterations": 10, + "times_ns": [ + 18124000, + 11232916, + 9714875, + 12087583, + 10636708, + 13601500, + 20622416, + 14261125, + 18720875, + 11364791 + ], + "mean_ns": 14036678.9, + "stddev_ns": 3623484.704021377, + "min_ns": 9714875, + "max_ns": 20622416, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "str_lowercase", + "category": "strings", + "iterations": 10, + "times_ns": [ + 50709, + 40625, + 37458, + 36458, + 36417, + 35375, + 37375, + 37625, + 36041, + 35041 + ], + "mean_ns": 38312.4, + "stddev_ns": 4388.918117258512, + "min_ns": 35041, + "max_ns": 50709, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "str_lowercase", + "category": "strings", + "iterations": 10, + "times_ns": [ + 12865208, + 5779917, + 19327542, + 21445667, + 11389042, + 8852084, + 9942583, + 9444958, + 6885292, + 6439667 + ], + "mean_ns": 11237196.0, + "stddev_ns": 5046327.426686382, + "min_ns": 5779917, + "max_ns": 21445667, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arr_create", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 45500, + 41458, + 39125, + 38417, + 37750, + 38042, + 37750, + 36000, + 35542, + 35750 + ], + "mean_ns": 38533.4, + "stddev_ns": 2864.1429852575448, + "min_ns": 35542, + "max_ns": 45500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arr_create", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 18998583, + 20772584, + 8793667, + 9894375, + 10486917, + 9543166, + 5967209, + 6882541, + 5769958, + 5791583 + ], + "mean_ns": 10290058.3, + "stddev_ns": 5095879.591600748, + "min_ns": 5769958, + "max_ns": 20772584, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arr_all", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 44458, + 39583, + 36625, + 35750, + 35208, + 35334, + 34584, + 34541, + 34375, + 36458 + ], + "mean_ns": 36691.6, + "stddev_ns": 2968.174833125569, + "min_ns": 34375, + "max_ns": 44458, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arr_all", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 7245125, + 9993167, + 13022584, + 5382708, + 7618792, + 8649041, + 5381667, + 5318833, + 6478959, + 5602292 + ], + "mean_ns": 7469316.8, + "stddev_ns": 2376475.102644242, + "min_ns": 5318833, + "max_ns": 13022584, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arr_length", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 43792, + 40500, + 38917, + 38084, + 37917, + 37917, + 42000, + 37750, + 38333, + 37666 + ], + "mean_ns": 39287.6, + "stddev_ns": 2009.0991613158371, + "min_ns": 37666, + "max_ns": 43792, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arr_length", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 5440625, + 6552750, + 6508875, + 6347250, + 8706750, + 8929917, + 6593291, + 5797333, + 6281583, + 5527875 + ], + "mean_ns": 6668624.9, + "stddev_ns": 1146016.7985995186, + "min_ns": 5440625, + "max_ns": 8929917, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arr_iterate", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 48209, + 44875, + 42958, + 41833, + 41667, + 41583, + 41250, + 40416, + 40917, + 40417 + ], + "mean_ns": 42412.5, + "stddev_ns": 2304.267964018074, + "min_ns": 40416, + "max_ns": 48209, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arr_iterate", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 5856709, + 6800750, + 6906250, + 5127458, + 5317875, + 8554750, + 5420333, + 6269500, + 5675000, + 5540083 + ], + "mean_ns": 6146870.8, + "stddev_ns": 987242.4203011944, + "min_ns": 5127458, + "max_ns": 8554750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arr_slice", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 49667, + 46459, + 44167, + 43125, + 43167, + 183375, + 163791, + 61250, + 50916, + 46833 + ], + "mean_ns": 73275.0, + "stddev_ns": 50594.55155844353, + "min_ns": 43125, + "max_ns": 183375, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arr_slice", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 5185291, + 5257750, + 5707000, + 10191625, + 7306750, + 5626833, + 8181458, + 6716750, + 7572125, + 5958250 + ], + "mean_ns": 6770383.2, + "stddev_ns": 1500933.41052032, + "min_ns": 5185291, + "max_ns": 10191625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "arr_assign_index", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 44958, + 41083, + 40500, + 39375, + 39125, + 38875, + 38583, + 38334, + 38834, + 38167 + ], + "mean_ns": 39783.4, + "stddev_ns": 1935.4653807288832, + "min_ns": 38167, + "max_ns": 44958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "arr_assign_index", + "category": "arrays", + "iterations": 10, + "times_ns": [ + 8879875, + 7624875, + 6927584, + 9166917, + 6908542, + 5829208, + 6970333, + 9177750, + 5647625, + 5741792 + ], + "mean_ns": 7287450.1, + "stddev_ns": 1316567.3443314969, + "min_ns": 5647625, + "max_ns": 9177750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "pipe_simple", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 55417, + 49416, + 51583, + 48333, + 49750, + 47167, + 46791, + 47125, + 46583, + 46292 + ], + "mean_ns": 48845.7, + "stddev_ns": 2715.188503584972, + "min_ns": 46292, + "max_ns": 55417, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "pipe_simple", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 20859833, + 17641000, + 12472417, + 11561250, + 14574000, + 11070333, + 16655000, + 13543667, + 16395125, + 15324708 + ], + "mean_ns": 15009733.3, + "stddev_ns": 2864624.798986005, + "min_ns": 11070333, + "max_ns": 20859833, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "pipe_multi", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 207334, + 318834, + 201625, + 98625, + 144000, + 115042, + 84708, + 79125, + 76666, + 75375 + ], + "mean_ns": 140133.4, + "stddev_ns": 75904.07053669782, + "min_ns": 75375, + "max_ns": 318834, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "pipe_multi", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 12939042, + 10710417, + 9775708, + 12552958, + 14018125, + 9342750, + 9466791, + 11172375, + 9156250, + 11854250 + ], + "mean_ns": 11098866.6, + "stddev_ns": 1613124.9727828405, + "min_ns": 9156250, + "max_ns": 14018125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "pipe_command_subst", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 41917, + 39208, + 38208, + 37125, + 37458, + 37084, + 36667, + 36166, + 36000, + 37083 + ], + "mean_ns": 37691.6, + "stddev_ns": 1666.5560416619658, + "min_ns": 36000, + "max_ns": 41917, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "pipe_command_subst", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 7157917, + 7467791, + 6616250, + 6577750, + 6431541, + 9506375, + 6135334, + 6643458, + 6252542, + 6368125 + ], + "mean_ns": 6915708.3, + "stddev_ns": 945307.6038357092, + "min_ns": 6135334, + "max_ns": 9506375, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "pipe_heredoc", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 41209, + 37417, + 36583, + 35750, + 35500, + 35167, + 35041, + 34708, + 34833, + 34084 + ], + "mean_ns": 36029.2, + "stddev_ns": 1951.9531654217526, + "min_ns": 34084, + "max_ns": 41209, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "pipe_heredoc", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 7794500, + 7755291, + 7578625, + 8641625, + 7595417, + 7563750, + 8816291, + 8781250, + 8244667, + 7259458 + ], + "mean_ns": 8003087.4, + "stddev_ns": 541313.7145654449, + "min_ns": 7259458, + "max_ns": 8816291, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "pipe_herestring", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 44083, + 41167, + 40625, + 37792, + 39167, + 38750, + 39667, + 74083, + 54792, + 44541 + ], + "mean_ns": 45466.7, + "stddev_ns": 10620.229235284896, + "min_ns": 37792, + "max_ns": 74083, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "pipe_herestring", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 9385542, + 8280334, + 8563208, + 7406625, + 7835417, + 10379458, + 7931375, + 10622042, + 8327584, + 10566167 + ], + "mean_ns": 8929775.2, + "stddev_ns": 1152563.9951363048, + "min_ns": 7406625, + "max_ns": 10622042, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "pipe_discard", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 47416, + 42375, + 40959, + 40625, + 40167, + 39708, + 40167, + 39750, + 39209, + 39208 + ], + "mean_ns": 40958.4, + "stddev_ns": 2328.5009856128468, + "min_ns": 39208, + "max_ns": 47416, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "pipe_discard", + "category": "pipes", + "iterations": 10, + "times_ns": [ + 7995000, + 8967750, + 8707458, + 9084333, + 8390625, + 7896500, + 8036833, + 7496958, + 6869625, + 10581125 + ], + "mean_ns": 8402620.7, + "stddev_ns": 966926.4516495606, + "min_ns": 6869625, + "max_ns": 10581125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_grep_simple", + "category": "tools", + "iterations": 10, + "times_ns": [ + 54958, + 50333, + 51291, + 48000, + 49875, + 47667, + 47750, + 49333, + 46792, + 46500 + ], + "mean_ns": 49249.9, + "stddev_ns": 2413.2965192864303, + "min_ns": 46500, + "max_ns": 54958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_grep_simple", + "category": "tools", + "iterations": 10, + "times_ns": [ + 16782334, + 16687167, + 13634500, + 14550875, + 10613750, + 11253875, + 8562833, + 10162000, + 13150500, + 12010583 + ], + "mean_ns": 12740841.7, + "stddev_ns": 2598554.5416324073, + "min_ns": 8562833, + "max_ns": 16782334, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_grep_case", + "category": "tools", + "iterations": 10, + "times_ns": [ + 98000, + 92625, + 324084, + 227542, + 102833, + 88958, + 82875, + 80542, + 77584, + 79084 + ], + "mean_ns": 125412.7, + "stddev_ns": 78627.42866589241, + "min_ns": 77584, + "max_ns": 324084, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_grep_case", + "category": "tools", + "iterations": 10, + "times_ns": [ + 12818042, + 14505542, + 10966125, + 13649792, + 14305833, + 9108250, + 8505916, + 9518292, + 7442125, + 9315416 + ], + "mean_ns": 11013533.3, + "stddev_ns": 2470511.613729393, + "min_ns": 7442125, + "max_ns": 14505542, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_grep_count", + "category": "tools", + "iterations": 10, + "times_ns": [ + 53916, + 50417, + 49167, + 47500, + 47292, + 47209, + 47542, + 47333, + 46417, + 46875 + ], + "mean_ns": 48366.8, + "stddev_ns": 2160.104710424937, + "min_ns": 46417, + "max_ns": 53916, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_grep_count", + "category": "tools", + "iterations": 10, + "times_ns": [ + 10280000, + 8340833, + 8172667, + 8832459, + 8424167, + 8852583, + 9702375, + 9743000, + 10498250, + 10979458 + ], + "mean_ns": 9382579.2, + "stddev_ns": 942522.3956702356, + "min_ns": 8172667, + "max_ns": 10979458, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_grep_invert", + "category": "tools", + "iterations": 10, + "times_ns": [ + 51292, + 46334, + 44875, + 43417, + 43625, + 43542, + 43792, + 42792, + 43042, + 42333 + ], + "mean_ns": 44504.4, + "stddev_ns": 2504.629920766739, + "min_ns": 42333, + "max_ns": 51292, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_grep_invert", + "category": "tools", + "iterations": 10, + "times_ns": [ + 9995250, + 9400875, + 9670541, + 9115041, + 9296584, + 8984209, + 9198125, + 8796291, + 7820000, + 11090916 + ], + "mean_ns": 9336783.2, + "stddev_ns": 800821.1891904209, + "min_ns": 7820000, + "max_ns": 11090916, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_grep_regex", + "category": "tools", + "iterations": 10, + "times_ns": [ + 61125, + 56000, + 54459, + 52250, + 52583, + 52083, + 52542, + 51834, + 51042, + 50708 + ], + "mean_ns": 53462.6, + "stddev_ns": 2953.6070219309813, + "min_ns": 50708, + "max_ns": 61125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_grep_regex", + "category": "tools", + "iterations": 10, + "times_ns": [ + 7748292, + 8400500, + 8701834, + 9598125, + 8334875, + 11919000, + 8293833, + 8989667, + 8416833, + 9121875 + ], + "mean_ns": 8952483.4, + "stddev_ns": 1103037.6016984372, + "min_ns": 7748292, + "max_ns": 11919000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_sed_replace", + "category": "tools", + "iterations": 10, + "times_ns": [ + 59334, + 45458, + 43125, + 40916, + 40375, + 39625, + 39500, + 38458, + 39125, + 38750 + ], + "mean_ns": 42466.6, + "stddev_ns": 5988.271740661074, + "min_ns": 38458, + "max_ns": 59334, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_sed_replace", + "category": "tools", + "iterations": 10, + "times_ns": [ + 7825791, + 8021125, + 11470916, + 8676500, + 8566291, + 9837875, + 8205417, + 8412500, + 11230458, + 8108125 + ], + "mean_ns": 9035499.8, + "stddev_ns": 1271671.3067434367, + "min_ns": 7825791, + "max_ns": 11470916, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_sed_global", + "category": "tools", + "iterations": 10, + "times_ns": [ + 43916, + 40750, + 39875, + 39167, + 37916, + 38000, + 38666, + 37500, + 37833, + 37292 + ], + "mean_ns": 39091.5, + "stddev_ns": 1917.1622909915582, + "min_ns": 37292, + "max_ns": 43916, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_sed_global", + "category": "tools", + "iterations": 10, + "times_ns": [ + 8399959, + 9005666, + 8526625, + 7645708, + 12126417, + 8796500, + 10861833, + 8562000, + 13518167, + 10020708 + ], + "mean_ns": 9746358.3, + "stddev_ns": 1782627.3975867222, + "min_ns": 7645708, + "max_ns": 13518167, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_sed_delete", + "category": "tools", + "iterations": 10, + "times_ns": [ + 45709, + 41750, + 40333, + 40083, + 38916, + 39000, + 38541, + 38292, + 38667, + 38333 + ], + "mean_ns": 39962.4, + "stddev_ns": 2180.2660479858873, + "min_ns": 38292, + "max_ns": 45709, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_sed_delete", + "category": "tools", + "iterations": 10, + "times_ns": [ + 7921708, + 7543041, + 8459584, + 8184291, + 8510083, + 8607417, + 7491084, + 7238542, + 7009292, + 7792709 + ], + "mean_ns": 7875775.1, + "stddev_ns": 528982.9196131856, + "min_ns": 7009292, + "max_ns": 8607417, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_sed_lines", + "category": "tools", + "iterations": 10, + "times_ns": [ + 43875, + 40792, + 39167, + 38792, + 38500, + 37792, + 38875, + 37625, + 38250, + 38084 + ], + "mean_ns": 39175.2, + "stddev_ns": 1782.0819734232205, + "min_ns": 37625, + "max_ns": 43875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_sed_lines", + "category": "tools", + "iterations": 10, + "times_ns": [ + 8694958, + 8990375, + 12216250, + 10684541, + 9913541, + 12951958, + 13535458, + 9959834, + 13984500, + 13512209 + ], + "mean_ns": 11444362.4, + "stddev_ns": 1915084.0806522937, + "min_ns": 8694958, + "max_ns": 13984500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_sed_backrefs", + "category": "tools", + "iterations": 10, + "times_ns": [ + 56542, + 51875, + 49208, + 48208, + 47709, + 47125, + 47334, + 47167, + 47375, + 47042 + ], + "mean_ns": 48958.5, + "stddev_ns": 2891.2425443051297, + "min_ns": 47042, + "max_ns": 56542, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_sed_backrefs", + "category": "tools", + "iterations": 10, + "times_ns": [ + 11880084, + 9605083, + 10771708, + 9951917, + 10646458, + 8987875, + 9964750, + 8147166, + 9230417, + 8567000 + ], + "mean_ns": 9775245.8, + "stddev_ns": 1063280.9760950112, + "min_ns": 8147166, + "max_ns": 11880084, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_awk_print", + "category": "tools", + "iterations": 10, + "times_ns": [ + 47750, + 43375, + 42542, + 45666, + 42208, + 40958, + 43625, + 40834, + 40417, + 41958 + ], + "mean_ns": 42933.3, + "stddev_ns": 2182.0361614785393, + "min_ns": 40417, + "max_ns": 47750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_awk_print", + "category": "tools", + "iterations": 10, + "times_ns": [ + 8291917, + 9153000, + 8831750, + 8200583, + 13030583, + 8665791, + 9664625, + 9008083, + 10280833, + 8148292 + ], + "mean_ns": 9327545.7, + "stddev_ns": 1388680.3330367324, + "min_ns": 8148292, + "max_ns": 13030583, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_awk_sum", + "category": "tools", + "iterations": 10, + "times_ns": [ + 51000, + 47583, + 45792, + 44417, + 44750, + 43542, + 43333, + 43208, + 43292, + 42458 + ], + "mean_ns": 44937.5, + "stddev_ns": 2473.002719367692, + "min_ns": 42458, + "max_ns": 51000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_awk_sum", + "category": "tools", + "iterations": 10, + "times_ns": [ + 9831917, + 8945125, + 8291541, + 9518458, + 11923625, + 8956167, + 8489834, + 8905250, + 8282792, + 10106208 + ], + "mean_ns": 9325091.7, + "stddev_ns": 1047177.0965776562, + "min_ns": 8282792, + "max_ns": 11923625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_awk_pattern", + "category": "tools", + "iterations": 10, + "times_ns": [ + 62792, + 93875, + 118750, + 70625, + 60875, + 57958, + 56042, + 53875, + 54709, + 52959 + ], + "mean_ns": 68246.0, + "stddev_ns": 20434.005955759138, + "min_ns": 52959, + "max_ns": 118750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_awk_pattern", + "category": "tools", + "iterations": 10, + "times_ns": [ + 10259375, + 7997666, + 7874541, + 8258834, + 7833417, + 7799166, + 7793917, + 7854875, + 7992791, + 7899125 + ], + "mean_ns": 8156370.7, + "stddev_ns": 713080.730036796, + "min_ns": 7793917, + "max_ns": 10259375, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_awk_fieldsep", + "category": "tools", + "iterations": 10, + "times_ns": [ + 51250, + 107166, + 68041, + 53458, + 48458, + 84375, + 151375, + 79541, + 45792, + 114542 + ], + "mean_ns": 80399.8, + "stddev_ns": 32988.52501037293, + "min_ns": 45792, + "max_ns": 151375, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_awk_fieldsep", + "category": "tools", + "iterations": 10, + "times_ns": [ + 9330416, + 10499458, + 9388875, + 9548958, + 10009625, + 10417666, + 13080500, + 11928500, + 13868875, + 10310959 + ], + "mean_ns": 10838383.2, + "stddev_ns": 1506448.4415761996, + "min_ns": 9330416, + "max_ns": 13868875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_awk_nf", + "category": "tools", + "iterations": 10, + "times_ns": [ + 54958, + 50792, + 48708, + 46125, + 45291, + 44916, + 46000, + 44458, + 44625, + 44209 + ], + "mean_ns": 47008.2, + "stddev_ns": 3309.7892923870545, + "min_ns": 44209, + "max_ns": 54958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_awk_nf", + "category": "tools", + "iterations": 10, + "times_ns": [ + 10231833, + 12322458, + 12233792, + 12655792, + 9243625, + 8702583, + 8642125, + 8538708, + 9806083, + 9983416 + ], + "mean_ns": 10236041.5, + "stddev_ns": 1523349.3138576753, + "min_ns": 8538708, + "max_ns": 12655792, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_awk_compute", + "category": "tools", + "iterations": 10, + "times_ns": [ + 66209, + 53750, + 49833, + 48000, + 47167, + 45541, + 45709, + 44958, + 44583, + 45125 + ], + "mean_ns": 49087.5, + "stddev_ns": 6303.554842309219, + "min_ns": 44583, + "max_ns": 66209, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_awk_compute", + "category": "tools", + "iterations": 10, + "times_ns": [ + 8605792, + 13675417, + 19473750, + 17122167, + 16465292, + 14883584, + 15330750, + 22826166, + 10463000, + 16325083 + ], + "mean_ns": 15517100.1, + "stddev_ns": 3877417.1800904647, + "min_ns": 8605792, + "max_ns": 22826166, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_jq_identity", + "category": "tools", + "iterations": 10, + "times_ns": [ + 394584, + 546958, + 371417, + 362667, + 359166, + 354834, + 352917, + 352166, + 352833, + 351708 + ], + "mean_ns": 379925.0, + "stddev_ns": 57075.211833159236, + "min_ns": 351708, + "max_ns": 546958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_jq_identity", + "category": "tools", + "iterations": 10, + "times_ns": [ + 11761708, + 10047041, + 8777250, + 11988583, + 11395833, + 11832000, + 14116250, + 11538416, + 14532584, + 12419708 + ], + "mean_ns": 11840937.3, + "stddev_ns": 1602467.552114117, + "min_ns": 8777250, + "max_ns": 14532584, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_jq_field", + "category": "tools", + "iterations": 10, + "times_ns": [ + 421875, + 731959, + 1277750, + 950292, + 529792, + 966542, + 860875, + 531333, + 466083, + 632042 + ], + "mean_ns": 736854.3, + "stddev_ns": 259791.03583074227, + "min_ns": 421875, + "max_ns": 1277750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_jq_field", + "category": "tools", + "iterations": 10, + "times_ns": [ + 17864917, + 15216500, + 12445292, + 14222459, + 12840792, + 21839292, + 11920500, + 12450709, + 14783000, + 11971917 + ], + "mean_ns": 14555537.8, + "stddev_ns": 3000782.113427158, + "min_ns": 11920500, + "max_ns": 21839292, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_jq_array", + "category": "tools", + "iterations": 10, + "times_ns": [ + 466708, + 414583, + 383875, + 369208, + 361791, + 356459, + 355625, + 354917, + 354417, + 352042 + ], + "mean_ns": 376962.5, + "stddev_ns": 35069.45039275637, + "min_ns": 352042, + "max_ns": 466708, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_jq_array", + "category": "tools", + "iterations": 10, + "times_ns": [ + 9878000, + 13623209, + 12509792, + 14403958, + 14936458, + 12747625, + 13171416, + 10916833, + 15179334, + 13763041 + ], + "mean_ns": 13112966.6, + "stddev_ns": 1604160.8414409198, + "min_ns": 9878000, + "max_ns": 15179334, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_jq_filter", + "category": "tools", + "iterations": 10, + "times_ns": [ + 415625, + 380958, + 374041, + 384792, + 362125, + 356625, + 354625, + 351125, + 814792, + 360750 + ], + "mean_ns": 415545.8, + "stddev_ns": 134332.31205543957, + "min_ns": 351125, + "max_ns": 814792, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_jq_filter", + "category": "tools", + "iterations": 10, + "times_ns": [ + 11575209, + 12425708, + 10486166, + 16786625, + 10301041, + 12587125, + 11521709, + 10821458, + 11554500, + 15724667 + ], + "mean_ns": 12378420.8, + "stddev_ns": 2074937.0938184992, + "min_ns": 10301041, + "max_ns": 16786625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "tool_jq_map", + "category": "tools", + "iterations": 10, + "times_ns": [ + 406833, + 369125, + 352916, + 348292, + 352209, + 349417, + 348625, + 348667, + 347167, + 350500 + ], + "mean_ns": 357375.1, + "stddev_ns": 17551.119072298497, + "min_ns": 347167, + "max_ns": 406833, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "tool_jq_map", + "category": "tools", + "iterations": 10, + "times_ns": [ + 14097750, + 12523042, + 11789584, + 10670750, + 10127084, + 11600083, + 15512875, + 15045875, + 14638500, + 11044875 + ], + "mean_ns": 12705041.8, + "stddev_ns": 1862090.4462771832, + "min_ns": 10127084, + "max_ns": 15512875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "complex_fibonacci", + "category": "complex", + "iterations": 10, + "times_ns": [ + 6305083, + 3449541, + 4238209, + 6038250, + 3748042, + 7698292, + 3418125, + 3553042, + 3723875, + 3891042 + ], + "mean_ns": 4606350.1, + "stddev_ns": 1432422.01469598, + "min_ns": 3418125, + "max_ns": 7698292, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "complex_fibonacci", + "category": "complex", + "iterations": 10, + "times_ns": [ + 215255416, + 188961458, + 280061375, + 215284541, + 190249125, + 283596459, + 203168083, + 201567292, + 187602417, + 174224291 + ], + "mean_ns": 213997045.7, + "stddev_ns": 35990100.19077229, + "min_ns": 174224291, + "max_ns": 283596459, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "complex_fibonacci_iter", + "category": "complex", + "iterations": 10, + "times_ns": [ + 368167, + 221792, + 95041, + 82583, + 82333, + 82167, + 80792, + 82083, + 80750, + 80084 + ], + "mean_ns": 125579.2, + "stddev_ns": 90895.06833904686, + "min_ns": 80084, + "max_ns": 368167, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "complex_fibonacci_iter", + "category": "complex", + "iterations": 10, + "times_ns": [ + 6144791, + 6031583, + 6303458, + 5665042, + 5477666, + 5671541, + 5566750, + 6320000, + 5403958, + 5131458 + ], + "mean_ns": 5771624.7, + "stddev_ns": 385376.1433796986, + "min_ns": 5131458, + "max_ns": 6320000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "complex_nested_subst", + "category": "complex", + "iterations": 10, + "times_ns": [ + 57875, + 54333, + 53709, + 49709, + 48542, + 48750, + 48333, + 48667, + 48917, + 45834 + ], + "mean_ns": 50466.9, + "stddev_ns": 3452.8887456736857, + "min_ns": 45834, + "max_ns": 57875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "complex_nested_subst", + "category": "complex", + "iterations": 10, + "times_ns": [ + 10565167, + 10135584, + 8423250, + 11139583, + 10146458, + 11058375, + 8421958, + 7467750, + 9581792, + 9139375 + ], + "mean_ns": 9607929.2, + "stddev_ns": 1163833.284356037, + "min_ns": 7467750, + "max_ns": 11139583, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "complex_loop_compute", + "category": "complex", + "iterations": 10, + "times_ns": [ + 80792, + 76625, + 74125, + 74167, + 73750, + 72042, + 72583, + 71125, + 72750, + 72583 + ], + "mean_ns": 74054.2, + "stddev_ns": 2660.3795518684924, + "min_ns": 71125, + "max_ns": 80792, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "complex_loop_compute", + "category": "complex", + "iterations": 10, + "times_ns": [ + 7843333, + 8239792, + 6897625, + 5672291, + 6622166, + 6778417, + 9208375, + 9859750, + 9508458, + 7336958 + ], + "mean_ns": 7796716.5, + "stddev_ns": 1316315.4925713858, + "min_ns": 5672291, + "max_ns": 9859750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "complex_string_build", + "category": "complex", + "iterations": 10, + "times_ns": [ + 52709, + 203625, + 170459, + 133167, + 74125, + 54959, + 50625, + 47333, + 46125, + 45084 + ], + "mean_ns": 87821.1, + "stddev_ns": 56021.45778619117, + "min_ns": 45084, + "max_ns": 203625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "complex_string_build", + "category": "complex", + "iterations": 10, + "times_ns": [ + 7617375, + 8904125, + 5743583, + 5782833, + 5392541, + 5782167, + 5510750, + 5693750, + 6411459, + 6162375 + ], + "mean_ns": 6300095.8, + "stddev_ns": 1058652.7582322543, + "min_ns": 5392541, + "max_ns": 8904125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "complex_json_transform", + "category": "complex", + "iterations": 10, + "times_ns": [ + 548500, + 452584, + 409042, + 382625, + 369583, + 361708, + 356583, + 354416, + 352917, + 373375 + ], + "mean_ns": 396133.3, + "stddev_ns": 58593.147524347936, + "min_ns": 352917, + "max_ns": 548500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "complex_json_transform", + "category": "complex", + "iterations": 10, + "times_ns": [ + 10302667, + 10475959, + 10255709, + 10378250, + 9725208, + 10115042, + 10588208, + 9193250, + 13350458, + 10978500 + ], + "mean_ns": 10536325.1, + "stddev_ns": 1044929.1309656794, + "min_ns": 9193250, + "max_ns": 13350458, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "complex_pipeline_text", + "category": "complex", + "iterations": 10, + "times_ns": [ + 69209, + 63292, + 60750, + 60041, + 59667, + 59250, + 117959, + 213167, + 252000, + 128375 + ], + "mean_ns": 108371.0, + "stddev_ns": 67125.15199237913, + "min_ns": 59250, + "max_ns": 252000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "complex_pipeline_text", + "category": "complex", + "iterations": 10, + "times_ns": [ + 9805625, + 9338709, + 9475667, + 10875500, + 13221666, + 14362625, + 9739000, + 13712958, + 11660250, + 13106208 + ], + "mean_ns": 11529820.8, + "stddev_ns": 1838035.9351432058, + "min_ns": 9338709, + "max_ns": 14362625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_loop_1000", + "category": "large", + "iterations": 10, + "times_ns": [ + 2538959, + 2560708, + 2979625, + 2891000, + 2527792, + 2481041, + 2393459, + 2282083, + 2486333, + 2390334 + ], + "mean_ns": 2553133.4, + "stddev_ns": 207864.59163946132, + "min_ns": 2282083, + "max_ns": 2979625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_loop_1000", + "category": "large", + "iterations": 10, + "times_ns": [ + 7779417, + 10117750, + 20590500, + 9261708, + 20419458, + 7842917, + 13205500, + 12285250, + 8080459, + 14699333 + ], + "mean_ns": 12428229.2, + "stddev_ns": 4617030.722911096, + "min_ns": 7779417, + "max_ns": 20590500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_string_append_100", + "category": "large", + "iterations": 10, + "times_ns": [ + 272417, + 260959, + 259542, + 257292, + 262291, + 255834, + 258125, + 256875, + 259208, + 472083 + ], + "mean_ns": 281462.6, + "stddev_ns": 63696.09426833014, + "min_ns": 255834, + "max_ns": 472083, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_string_append_100", + "category": "large", + "iterations": 10, + "times_ns": [ + 7603459, + 6154792, + 5877209, + 6428333, + 6016125, + 7401875, + 6418416, + 6123125, + 5919041, + 5796958 + ], + "mean_ns": 6373933.3, + "stddev_ns": 599904.3796641346, + "min_ns": 5796958, + "max_ns": 7603459, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_array_fill_200", + "category": "large", + "iterations": 10, + "times_ns": [ + 1083500, + 997750, + 1025250, + 1006875, + 1007709, + 1005750, + 1008916, + 1015292, + 998959, + 1005375 + ], + "mean_ns": 1015537.6, + "stddev_ns": 23840.671748925193, + "min_ns": 997750, + "max_ns": 1083500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_array_fill_200", + "category": "large", + "iterations": 10, + "times_ns": [ + 9398916, + 8016250, + 5856125, + 6056500, + 5736375, + 5612375, + 6394584, + 5771417, + 5769500, + 6002625 + ], + "mean_ns": 6461466.7, + "stddev_ns": 1182924.6084984497, + "min_ns": 5612375, + "max_ns": 9398916, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_nested_loops", + "category": "large", + "iterations": 10, + "times_ns": [ + 1226125, + 1184417, + 1140416, + 1192083, + 1203416, + 1178583, + 1130084, + 1132792, + 1139458, + 1283500 + ], + "mean_ns": 1181087.4, + "stddev_ns": 46340.604333996336, + "min_ns": 1130084, + "max_ns": 1283500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_nested_loops", + "category": "large", + "iterations": 10, + "times_ns": [ + 6499209, + 6055209, + 6341833, + 6850875, + 7131334, + 9181333, + 6983417, + 6686041, + 7559209, + 8049166 + ], + "mean_ns": 7133762.6, + "stddev_ns": 877934.5602344403, + "min_ns": 6055209, + "max_ns": 9181333, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_fibonacci_12", + "category": "large", + "iterations": 10, + "times_ns": [ + 10367917, + 15805541, + 119625625, + 9287958, + 248930000, + 77414708, + 53966000, + 132353500, + 117956542, + 23080334 + ], + "mean_ns": 80878812.5, + "stddev_ns": 72232575.53673065, + "min_ns": 9287958, + "max_ns": 248930000, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_fibonacci_12", + "category": "large", + "iterations": 10, + "times_ns": [ + 501716667, + 636463250, + 704043125, + 661982791, + 816058625, + 979291292, + 799355042, + 768302083, + 623326333, + 808915959 + ], + "mean_ns": 729945516.7, + "stddev_ns": 126332450.52430671, + "min_ns": 501716667, + "max_ns": 979291292, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_function_calls_500", + "category": "large", + "iterations": 10, + "times_ns": [ + 5796291, + 5640958, + 4725458, + 4749625, + 4757833, + 4723750, + 4725875, + 4828875, + 4967416, + 5114375 + ], + "mean_ns": 5003045.6, + "stddev_ns": 378999.37537684676, + "min_ns": 4723750, + "max_ns": 5796291, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_function_calls_500", + "category": "large", + "iterations": 10, + "times_ns": [ + 954672250, + 784846750, + 995216958, + 876543709, + 896436375, + 1071348750, + 405605416, + 407808250, + 385927292, + 390659625 + ], + "mean_ns": 716906537.5, + "stddev_ns": 270256140.76342076, + "min_ns": 385927292, + "max_ns": 1071348750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_multiline_script", + "category": "large", + "iterations": 10, + "times_ns": [ + 239167, + 232750, + 228417, + 226584, + 226917, + 224875, + 226667, + 223792, + 226666, + 223750 + ], + "mean_ns": 227958.5, + "stddev_ns": 4468.678042777305, + "min_ns": 223750, + "max_ns": 239167, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_multiline_script", + "category": "large", + "iterations": 10, + "times_ns": [ + 6547750, + 5910333, + 5728333, + 5581416, + 5844792, + 6070750, + 6009208, + 7850667, + 5872625, + 6254917 + ], + "mean_ns": 6167079.1, + "stddev_ns": 617518.1605586106, + "min_ns": 5581416, + "max_ns": 7850667, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_pipeline_chain", + "category": "large", + "iterations": 10, + "times_ns": [ + 671875, + 630000, + 581000, + 565958, + 561333, + 562291, + 555625, + 556667, + 555166, + 555209 + ], + "mean_ns": 579512.4, + "stddev_ns": 37641.429532365, + "min_ns": 555166, + "max_ns": 671875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_pipeline_chain", + "category": "large", + "iterations": 10, + "times_ns": [ + 8894500, + 12981958, + 9882083, + 9532209, + 8353250, + 8488709, + 9122292, + 8587333, + 7950208, + 8728500 + ], + "mean_ns": 9252104.2, + "stddev_ns": 1354016.257448765, + "min_ns": 7950208, + "max_ns": 12981958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "large_assoc_array", + "category": "large", + "iterations": 10, + "times_ns": [ + 52083, + 47583, + 46583, + 45125, + 45875, + 45333, + 45083, + 45083, + 45125, + 44709 + ], + "mean_ns": 46258.2, + "stddev_ns": 2110.0288528832966, + "min_ns": 44709, + "max_ns": 52083, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "large_assoc_array", + "category": "large", + "iterations": 10, + "times_ns": [ + 5613959, + 5526208, + 5760583, + 5762708, + 5831791, + 5919042, + 5953750, + 5555625, + 5738459, + 5842625 + ], + "mean_ns": 5750475.0, + "stddev_ns": 138612.59095911885, + "min_ns": 5526208, + "max_ns": 5953750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "subshell_simple", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 43291, + 40083, + 37917, + 37375, + 36500, + 36333, + 36125, + 36792, + 36209, + 36375 + ], + "mean_ns": 37700.0, + "stddev_ns": 2183.6475906152987, + "min_ns": 36125, + "max_ns": 43291, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "subshell_simple", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 27336875, + 49113916, + 63764042, + 7226791, + 7172875, + 24811750, + 13973208, + 6416542, + 37689500, + 7584125 + ], + "mean_ns": 24508962.4, + "stddev_ns": 19110681.96023566, + "min_ns": 6416542, + "max_ns": 63764042, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "subshell_isolation", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 44333, + 40958, + 39625, + 38583, + 38917, + 38625, + 39333, + 38875, + 38334, + 38375 + ], + "mean_ns": 39595.8, + "stddev_ns": 1743.4907398664325, + "min_ns": 38334, + "max_ns": 44333, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "subshell_isolation", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 7065375, + 7652166, + 7355042, + 6707458, + 6609459, + 7731375, + 23833292, + 24676167, + 26887750, + 6414875 + ], + "mean_ns": 12493295.9, + "stddev_ns": 8314067.800642024, + "min_ns": 6414875, + "max_ns": 26887750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "subshell_nested", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 54917, + 91917, + 61500, + 54458, + 52417, + 51292, + 50917, + 50166, + 73250, + 52417 + ], + "mean_ns": 59325.1, + "stddev_ns": 12722.203539088658, + "min_ns": 50166, + "max_ns": 91917, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "subshell_nested", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 8249458, + 10466917, + 8307958, + 8827709, + 8723166, + 8543833, + 7911417, + 8281333, + 8355875, + 8628541 + ], + "mean_ns": 8629620.7, + "stddev_ns": 662650.454081343, + "min_ns": 7911417, + "max_ns": 10466917, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "subshell_pipeline", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 53625, + 49000, + 47042, + 45792, + 45833, + 45250, + 45125, + 45750, + 45458, + 45375 + ], + "mean_ns": 46825.0, + "stddev_ns": 2521.2359270802085, + "min_ns": 45125, + "max_ns": 53625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "subshell_pipeline", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 8348875, + 7563416, + 7735584, + 7664459, + 8114500, + 9363625, + 8557625, + 8686334, + 8389917, + 7745750 + ], + "mean_ns": 8217008.5, + "stddev_ns": 538066.7029180025, + "min_ns": 7563416, + "max_ns": 9363625, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "subshell_capture_loop", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 74833, + 70833, + 69292, + 68125, + 68083, + 68042, + 68000, + 67917, + 68042, + 67458 + ], + "mean_ns": 69062.5, + "stddev_ns": 2131.25959235378, + "min_ns": 67458, + "max_ns": 74833, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "subshell_capture_loop", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 9214791, + 8992709, + 9465875, + 9061500, + 9005208, + 9271000, + 9316041, + 8943458, + 9045917, + 8820625 + ], + "mean_ns": 9113712.4, + "stddev_ns": 186691.13398134365, + "min_ns": 8820625, + "max_ns": 9465875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "subshell_process_subst", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 56083, + 52917, + 51084, + 50209, + 50042, + 49584, + 49541, + 49458, + 49709, + 48958 + ], + "mean_ns": 50758.5, + "stddev_ns": 2069.468591208864, + "min_ns": 48958, + "max_ns": 56083, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "subshell_process_subst", + "category": "subshell", + "iterations": 10, + "times_ns": [ + 6960125, + 8051458, + 7329000, + 7248292, + 6943750, + 7238917, + 7085750, + 6847333, + 7255917, + 7799875 + ], + "mean_ns": 7276041.7, + "stddev_ns": 362112.255323691, + "min_ns": 6847333, + "max_ns": 8051458, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "io_redirect_write", + "category": "io", + "iterations": 10, + "times_ns": [ + 60791, + 56083, + 54250, + 53041, + 53042, + 52291, + 51917, + 51875, + 51500, + 52084 + ], + "mean_ns": 53687.4, + "stddev_ns": 2703.249496439424, + "min_ns": 51500, + "max_ns": 60791, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "io_redirect_write", + "category": "io", + "iterations": 10, + "times_ns": [ + 9870125, + 10243959, + 9331000, + 9452542, + 9253750, + 15721875, + 9504917, + 9933375, + 9191459, + 9245750 + ], + "mean_ns": 10174875.2, + "stddev_ns": 1878477.0872209114, + "min_ns": 9191459, + "max_ns": 15721875, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "io_append", + "category": "io", + "iterations": 10, + "times_ns": [ + 71750, + 67208, + 65541, + 64041, + 64125, + 63458, + 63666, + 63542, + 63167, + 63625 + ], + "mean_ns": 65012.3, + "stddev_ns": 2528.7909383735146, + "min_ns": 63167, + "max_ns": 71750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "io_append", + "category": "io", + "iterations": 10, + "times_ns": [ + 9299917, + 9624125, + 9777041, + 9750375, + 9586708, + 9269500, + 9427000, + 9730792, + 8799125, + 9433500 + ], + "mean_ns": 9469808.3, + "stddev_ns": 282958.4212360714, + "min_ns": 8799125, + "max_ns": 9777041, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "io_dev_null", + "category": "io", + "iterations": 10, + "times_ns": [ + 39125, + 36125, + 35583, + 34792, + 34334, + 33792, + 34250, + 34417, + 34167, + 33917 + ], + "mean_ns": 35050.2, + "stddev_ns": 1526.8002357872492, + "min_ns": 33792, + "max_ns": 39125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "io_dev_null", + "category": "io", + "iterations": 10, + "times_ns": [ + 5675958, + 5320375, + 5422584, + 5071791, + 5092708, + 4508542, + 5177084, + 4575417, + 5266750, + 5717375 + ], + "mean_ns": 5182858.4, + "stddev_ns": 381635.4618897987, + "min_ns": 4508542, + "max_ns": 5717375, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "io_stderr_redirect", + "category": "io", + "iterations": 10, + "times_ns": [ + 38125, + 35584, + 34334, + 33667, + 33917, + 33500, + 34125, + 33167, + 33375, + 32625 + ], + "mean_ns": 34241.9, + "stddev_ns": 1496.9843987162992, + "min_ns": 32625, + "max_ns": 38125, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "io_stderr_redirect", + "category": "io", + "iterations": 10, + "times_ns": [ + 4820959, + 5132625, + 5296292, + 5373000, + 5052500, + 5320875, + 5501500, + 5268459, + 4808708, + 5285791 + ], + "mean_ns": 5186070.9, + "stddev_ns": 218608.74789287368, + "min_ns": 4808708, + "max_ns": 5501500, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "io_read_lines", + "category": "io", + "iterations": 10, + "times_ns": [ + 68958, + 64542, + 64125, + 62667, + 61542, + 61875, + 61584, + 61125, + 61500, + 60500 + ], + "mean_ns": 62841.8, + "stddev_ns": 2375.1597756782594, + "min_ns": 60500, + "max_ns": 68958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "io_read_lines", + "category": "io", + "iterations": 10, + "times_ns": [ + 4891458, + 5619750, + 5389584, + 5112167, + 5203500, + 5507917, + 5630750, + 5189042, + 5265375, + 5165917 + ], + "mean_ns": 5297546.0, + "stddev_ns": 224904.21221400012, + "min_ns": 4891458, + "max_ns": 5630750, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bashkit", + "case_name": "io_multiline_heredoc", + "category": "io", + "iterations": 10, + "times_ns": [ + 48958, + 44791, + 43250, + 42416, + 41125, + 40875, + 40833, + 41041, + 41042, + 40458 + ], + "mean_ns": 42478.9, + "stddev_ns": 2515.0327413375758, + "min_ns": 40458, + "max_ns": 48958, + "errors": 0, + "error_messages": [], + "output_match": true + }, + { + "runner": "bash", + "case_name": "io_multiline_heredoc", + "category": "io", + "iterations": 10, + "times_ns": [ + 7867167, + 7700750, + 7832666, + 7446958, + 7541000, + 8201791, + 8433917, + 7574917, + 7321375, + 7975333 + ], + "mean_ns": 7789587.4, + "stddev_ns": 328608.75616672175, + "min_ns": 7321375, + "max_ns": 8433917, + "errors": 0, + "error_messages": [], + "output_match": true + } + ], + "summary": { + "total_cases": 96, + "runner_stats": { + "bashkit": { + "total_time_ms": 103.2032474, + "avg_time_ms": 1.0750338270833333, + "error_count": 0, + "error_rate": 0.0, + "output_match_rate": 1.0 + }, + "bash": { + "total_time_ms": 2463.2769903999992, + "avg_time_ms": 25.65913531666666, + "error_count": 0, + "error_rate": 0.0, + "output_match_rate": 1.0 + } + } + } +} \ No newline at end of file diff --git a/crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.md b/crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.md new file mode 100644 index 000000000..1ee3594cc --- /dev/null +++ b/crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.md @@ -0,0 +1,308 @@ +# Bashkit Benchmark Report + +## System Information + +- **Moniker**: `mykhailosmin-macos-aarch64` +- **Hostname**: Mykhailos-Mini.lan +- **OS**: macos +- **Architecture**: aarch64 +- **CPUs**: 12 +- **Timestamp**: 1791865783 +- **Iterations**: 10 +- **Warmup**: 2 +- **Prewarm cases**: 3 + +- **bash executable**: `/opt/homebrew/bin/bash (GNU Bash 5.3.20(1)-release)` + +## Summary + +Benchmarked 96 cases across 2 runners. + +| Runner | Total Time (ms) | Avg/Case (ms) | Errors | Error Rate | Output Match | +|--------|-----------------|---------------|--------|------------|-------------| +| bashkit | 103.20 | 1.075 | 0 | 0.0% | 100.0% | +| bash | 2463.28 | 25.659 | 0 | 0.0% | 100.0% | + +## Performance Comparison + +**Bashkit is 23.9x faster** than bash on average. + +## Results by Category + +### Arithmetic + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| arith_basic | bashkit | 0.033 | ±0.001 | - | ✓ | +| arith_basic | bash | 4.974 | ±0.256 | - | ✓ | +| arith_complex | bashkit | 0.032 | ±0.002 | - | ✓ | +| arith_complex | bash | 4.819 | ±0.302 | - | ✓ | +| arith_variables | bashkit | 0.036 | ±0.002 | - | ✓ | +| arith_variables | bash | 4.629 | ±0.359 | - | ✓ | +| arith_increment | bashkit | 0.035 | ±0.002 | - | ✓ | +| arith_increment | bash | 4.540 | ±0.348 | - | ✓ | +| arith_modulo | bashkit | 0.031 | ±0.001 | - | ✓ | +| arith_modulo | bash | 4.750 | ±0.145 | - | ✓ | +| arith_loop_sum | bashkit | 0.054 | ±0.002 | - | ✓ | +| arith_loop_sum | bash | 4.896 | ±0.291 | - | ✓ | + +### Arrays + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| arr_create | bashkit | 0.039 | ±0.003 | - | ✓ | +| arr_create | bash | 10.290 | ±5.096 | - | ✓ | +| arr_all | bashkit | 0.037 | ±0.003 | - | ✓ | +| arr_all | bash | 7.469 | ±2.376 | - | ✓ | +| arr_length | bashkit | 0.039 | ±0.002 | - | ✓ | +| arr_length | bash | 6.669 | ±1.146 | - | ✓ | +| arr_iterate | bashkit | 0.042 | ±0.002 | - | ✓ | +| arr_iterate | bash | 6.147 | ±0.987 | - | ✓ | +| arr_slice | bashkit | 0.073 | ±0.051 | - | ✓ | +| arr_slice | bash | 6.770 | ±1.501 | - | ✓ | +| arr_assign_index | bashkit | 0.040 | ±0.002 | - | ✓ | +| arr_assign_index | bash | 7.287 | ±1.317 | - | ✓ | + +### Complex + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| complex_fibonacci | bashkit | 4.606 | ±1.432 | - | ✓ | +| complex_fibonacci | bash | 213.997 | ±35.990 | - | ✓ | +| complex_fibonacci_iter | bashkit | 0.126 | ±0.091 | - | ✓ | +| complex_fibonacci_iter | bash | 5.772 | ±0.385 | - | ✓ | +| complex_nested_subst | bashkit | 0.050 | ±0.003 | - | ✓ | +| complex_nested_subst | bash | 9.608 | ±1.164 | - | ✓ | +| complex_loop_compute | bashkit | 0.074 | ±0.003 | - | ✓ | +| complex_loop_compute | bash | 7.797 | ±1.316 | - | ✓ | +| complex_string_build | bashkit | 0.088 | ±0.056 | - | ✓ | +| complex_string_build | bash | 6.300 | ±1.059 | - | ✓ | +| complex_json_transform | bashkit | 0.396 | ±0.059 | - | ✓ | +| complex_json_transform | bash | 10.536 | ±1.045 | - | ✓ | +| complex_pipeline_text | bashkit | 0.108 | ±0.067 | - | ✓ | +| complex_pipeline_text | bash | 11.530 | ±1.838 | - | ✓ | + +### Control + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| ctrl_if_simple | bashkit | 0.034 | ±0.001 | - | ✓ | +| ctrl_if_simple | bash | 7.276 | ±4.271 | - | ✓ | +| ctrl_if_else | bashkit | 0.036 | ±0.002 | - | ✓ | +| ctrl_if_else | bash | 13.713 | ±5.608 | - | ✓ | +| ctrl_for_list | bashkit | 0.062 | ±0.023 | - | ✓ | +| ctrl_for_list | bash | 13.661 | ±4.050 | - | ✓ | +| ctrl_for_range | bashkit | 0.055 | ±0.003 | - | ✓ | +| ctrl_for_range | bash | 7.842 | ±2.122 | - | ✓ | +| ctrl_while | bashkit | 0.078 | ±0.010 | - | ✓ | +| ctrl_while | bash | 11.540 | ±1.850 | - | ✓ | +| ctrl_case | bashkit | 0.037 | ±0.002 | - | ✓ | +| ctrl_case | bash | 15.494 | ±4.938 | - | ✓ | +| ctrl_function | bashkit | 0.055 | ±0.043 | - | ✓ | +| ctrl_function | bash | 7.837 | ±1.868 | - | ✓ | +| ctrl_function_return | bashkit | 0.046 | ±0.003 | - | ✓ | +| ctrl_function_return | bash | 7.614 | ±1.520 | - | ✓ | +| ctrl_nested_loops | bashkit | 0.065 | ±0.004 | - | ✓ | +| ctrl_nested_loops | bash | 7.723 | ±2.009 | - | ✓ | + +### Io + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| io_redirect_write | bashkit | 0.054 | ±0.003 | - | ✓ | +| io_redirect_write | bash | 10.175 | ±1.878 | - | ✓ | +| io_append | bashkit | 0.065 | ±0.003 | - | ✓ | +| io_append | bash | 9.470 | ±0.283 | - | ✓ | +| io_dev_null | bashkit | 0.035 | ±0.002 | - | ✓ | +| io_dev_null | bash | 5.183 | ±0.382 | - | ✓ | +| io_stderr_redirect | bashkit | 0.034 | ±0.001 | - | ✓ | +| io_stderr_redirect | bash | 5.186 | ±0.219 | - | ✓ | +| io_read_lines | bashkit | 0.063 | ±0.002 | - | ✓ | +| io_read_lines | bash | 5.298 | ±0.225 | - | ✓ | +| io_multiline_heredoc | bashkit | 0.042 | ±0.003 | - | ✓ | +| io_multiline_heredoc | bash | 7.790 | ±0.329 | - | ✓ | + +### Large + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| large_loop_1000 | bashkit | 2.553 | ±0.208 | - | ✓ | +| large_loop_1000 | bash | 12.428 | ±4.617 | - | ✓ | +| large_string_append_100 | bashkit | 0.281 | ±0.064 | - | ✓ | +| large_string_append_100 | bash | 6.374 | ±0.600 | - | ✓ | +| large_array_fill_200 | bashkit | 1.016 | ±0.024 | - | ✓ | +| large_array_fill_200 | bash | 6.461 | ±1.183 | - | ✓ | +| large_nested_loops | bashkit | 1.181 | ±0.046 | - | ✓ | +| large_nested_loops | bash | 7.134 | ±0.878 | - | ✓ | +| large_fibonacci_12 | bashkit | 80.879 | ±72.233 | - | ✓ | +| large_fibonacci_12 | bash | 729.946 | ±126.332 | - | ✓ | +| large_function_calls_500 | bashkit | 5.003 | ±0.379 | - | ✓ | +| large_function_calls_500 | bash | 716.907 | ±270.256 | - | ✓ | +| large_multiline_script | bashkit | 0.228 | ±0.004 | - | ✓ | +| large_multiline_script | bash | 6.167 | ±0.618 | - | ✓ | +| large_pipeline_chain | bashkit | 0.580 | ±0.038 | - | ✓ | +| large_pipeline_chain | bash | 9.252 | ±1.354 | - | ✓ | +| large_assoc_array | bashkit | 0.046 | ±0.002 | - | ✓ | +| large_assoc_array | bash | 5.750 | ±0.139 | - | ✓ | + +### Pipes + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| pipe_simple | bashkit | 0.049 | ±0.003 | - | ✓ | +| pipe_simple | bash | 15.010 | ±2.865 | - | ✓ | +| pipe_multi | bashkit | 0.140 | ±0.076 | - | ✓ | +| pipe_multi | bash | 11.099 | ±1.613 | - | ✓ | +| pipe_command_subst | bashkit | 0.038 | ±0.002 | - | ✓ | +| pipe_command_subst | bash | 6.916 | ±0.945 | - | ✓ | +| pipe_heredoc | bashkit | 0.036 | ±0.002 | - | ✓ | +| pipe_heredoc | bash | 8.003 | ±0.541 | - | ✓ | +| pipe_herestring | bashkit | 0.045 | ±0.011 | - | ✓ | +| pipe_herestring | bash | 8.930 | ±1.153 | - | ✓ | +| pipe_discard | bashkit | 0.041 | ±0.002 | - | ✓ | +| pipe_discard | bash | 8.403 | ±0.967 | - | ✓ | + +### Startup + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| startup_empty | bashkit | 0.030 | ±0.001 | - | ✓ | +| startup_empty | bash | 4.658 | ±0.230 | - | ✓ | +| startup_true | bashkit | 0.030 | ±0.001 | - | ✓ | +| startup_true | bash | 5.096 | ±0.579 | - | ✓ | +| startup_echo | bashkit | 0.032 | ±0.002 | - | ✓ | +| startup_echo | bash | 4.849 | ±0.126 | - | ✓ | +| startup_exit | bashkit | 0.031 | ±0.002 | - | ✓ | +| startup_exit | bash | 4.719 | ±0.266 | - | ✓ | + +### Strings + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| str_concat | bashkit | 0.068 | ±0.048 | - | ✓ | +| str_concat | bash | 7.650 | ±1.647 | - | ✓ | +| str_printf | bashkit | 0.035 | ±0.002 | - | ✓ | +| str_printf | bash | 8.740 | ±2.011 | - | ✓ | +| str_printf_pad | bashkit | 0.112 | ±0.056 | - | ✓ | +| str_printf_pad | bash | 7.947 | ±2.054 | - | ✓ | +| str_echo_escape | bashkit | 0.032 | ±0.002 | - | ✓ | +| str_echo_escape | bash | 10.109 | ±2.861 | - | ✓ | +| str_prefix_strip | bashkit | 0.099 | ±0.044 | - | ✓ | +| str_prefix_strip | bash | 8.303 | ±1.163 | - | ✓ | +| str_suffix_strip | bashkit | 0.091 | ±0.144 | - | ✓ | +| str_suffix_strip | bash | 8.795 | ±3.834 | - | ✓ | +| str_uppercase | bashkit | 0.073 | ±0.045 | - | ✓ | +| str_uppercase | bash | 14.037 | ±3.623 | - | ✓ | +| str_lowercase | bashkit | 0.038 | ±0.004 | - | ✓ | +| str_lowercase | bash | 11.237 | ±5.046 | - | ✓ | + +### Subshell + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| subshell_simple | bashkit | 0.038 | ±0.002 | - | ✓ | +| subshell_simple | bash | 24.509 | ±19.111 | - | ✓ | +| subshell_isolation | bashkit | 0.040 | ±0.002 | - | ✓ | +| subshell_isolation | bash | 12.493 | ±8.314 | - | ✓ | +| subshell_nested | bashkit | 0.059 | ±0.013 | - | ✓ | +| subshell_nested | bash | 8.630 | ±0.663 | - | ✓ | +| subshell_pipeline | bashkit | 0.047 | ±0.003 | - | ✓ | +| subshell_pipeline | bash | 8.217 | ±0.538 | - | ✓ | +| subshell_capture_loop | bashkit | 0.069 | ±0.002 | - | ✓ | +| subshell_capture_loop | bash | 9.114 | ±0.187 | - | ✓ | +| subshell_process_subst | bashkit | 0.051 | ±0.002 | - | ✓ | +| subshell_process_subst | bash | 7.276 | ±0.362 | - | ✓ | + +### Tools + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| tool_grep_simple | bashkit | 0.049 | ±0.002 | - | ✓ | +| tool_grep_simple | bash | 12.741 | ±2.599 | - | ✓ | +| tool_grep_case | bashkit | 0.125 | ±0.079 | - | ✓ | +| tool_grep_case | bash | 11.014 | ±2.471 | - | ✓ | +| tool_grep_count | bashkit | 0.048 | ±0.002 | - | ✓ | +| tool_grep_count | bash | 9.383 | ±0.943 | - | ✓ | +| tool_grep_invert | bashkit | 0.045 | ±0.003 | - | ✓ | +| tool_grep_invert | bash | 9.337 | ±0.801 | - | ✓ | +| tool_grep_regex | bashkit | 0.053 | ±0.003 | - | ✓ | +| tool_grep_regex | bash | 8.952 | ±1.103 | - | ✓ | +| tool_sed_replace | bashkit | 0.042 | ±0.006 | - | ✓ | +| tool_sed_replace | bash | 9.035 | ±1.272 | - | ✓ | +| tool_sed_global | bashkit | 0.039 | ±0.002 | - | ✓ | +| tool_sed_global | bash | 9.746 | ±1.783 | - | ✓ | +| tool_sed_delete | bashkit | 0.040 | ±0.002 | - | ✓ | +| tool_sed_delete | bash | 7.876 | ±0.529 | - | ✓ | +| tool_sed_lines | bashkit | 0.039 | ±0.002 | - | ✓ | +| tool_sed_lines | bash | 11.444 | ±1.915 | - | ✓ | +| tool_sed_backrefs | bashkit | 0.049 | ±0.003 | - | ✓ | +| tool_sed_backrefs | bash | 9.775 | ±1.063 | - | ✓ | +| tool_awk_print | bashkit | 0.043 | ±0.002 | - | ✓ | +| tool_awk_print | bash | 9.328 | ±1.389 | - | ✓ | +| tool_awk_sum | bashkit | 0.045 | ±0.002 | - | ✓ | +| tool_awk_sum | bash | 9.325 | ±1.047 | - | ✓ | +| tool_awk_pattern | bashkit | 0.068 | ±0.020 | - | ✓ | +| tool_awk_pattern | bash | 8.156 | ±0.713 | - | ✓ | +| tool_awk_fieldsep | bashkit | 0.080 | ±0.033 | - | ✓ | +| tool_awk_fieldsep | bash | 10.838 | ±1.506 | - | ✓ | +| tool_awk_nf | bashkit | 0.047 | ±0.003 | - | ✓ | +| tool_awk_nf | bash | 10.236 | ±1.523 | - | ✓ | +| tool_awk_compute | bashkit | 0.049 | ±0.006 | - | ✓ | +| tool_awk_compute | bash | 15.517 | ±3.877 | - | ✓ | +| tool_jq_identity | bashkit | 0.380 | ±0.057 | - | ✓ | +| tool_jq_identity | bash | 11.841 | ±1.602 | - | ✓ | +| tool_jq_field | bashkit | 0.737 | ±0.260 | - | ✓ | +| tool_jq_field | bash | 14.556 | ±3.001 | - | ✓ | +| tool_jq_array | bashkit | 0.377 | ±0.035 | - | ✓ | +| tool_jq_array | bash | 13.113 | ±1.604 | - | ✓ | +| tool_jq_filter | bashkit | 0.416 | ±0.134 | - | ✓ | +| tool_jq_filter | bash | 12.378 | ±2.075 | - | ✓ | +| tool_jq_map | bashkit | 0.357 | ±0.018 | - | ✓ | +| tool_jq_map | bash | 12.705 | ±1.862 | - | ✓ | + +### Variables + +| Benchmark | Runner | Mean (ms) | StdDev | Errors | Match | +|-----------|--------|-----------|--------|--------|-------| +| var_assign_simple | bashkit | 0.035 | ±0.002 | - | ✓ | +| var_assign_simple | bash | 4.907 | ±0.236 | - | ✓ | +| var_assign_many | bashkit | 0.045 | ±0.002 | - | ✓ | +| var_assign_many | bash | 4.208 | ±0.138 | - | ✓ | +| var_default | bashkit | 0.031 | ±0.002 | - | ✓ | +| var_default | bash | 4.172 | ±0.178 | - | ✓ | +| var_length | bashkit | 0.031 | ±0.002 | - | ✓ | +| var_length | bash | 4.629 | ±0.363 | - | ✓ | +| var_substring | bashkit | 0.035 | ±0.005 | - | ✓ | +| var_substring | bash | 4.321 | ±0.154 | - | ✓ | +| var_replace | bashkit | 0.035 | ±0.003 | - | ✓ | +| var_replace | bash | 4.368 | ±0.186 | - | ✓ | +| var_nested | bashkit | 0.034 | ±0.002 | - | ✓ | +| var_nested | bash | 4.845 | ±0.414 | - | ✓ | +| var_export | bashkit | 0.036 | ±0.003 | - | ✓ | +| var_export | bash | 4.791 | ±0.206 | - | ✓ | + +## Runner Descriptions + +| Runner | Type | Description | +|--------|------|-------------| +| bashkit | in-process | Rust library call, no fork/exec | +| bashkit-cli | subprocess | bashkit binary, new process per run | +| bashkit-js | persistent child | Node.js + @everruns/bashkit, warm interpreter | +| bashkit-py | persistent child | Python + bashkit package, warm interpreter | +| bash | subprocess | PATH-selected Bash >=4, new process per run | +| gbash | subprocess | gbash binary (Go), new process per run | +| gbash-server | persistent child | gbash JSON-RPC server, warm interpreter | +| just-bash | subprocess | just-bash CLI, new process per run | +| just-bash-inproc | persistent child | Node.js + just-bash library, warm interpreter | + +## Assumptions & Notes + +- Times measured in nanoseconds, displayed in milliseconds +- Prewarm phase runs first few cases to warm up JIT/compilation +- Per-benchmark warmup iterations excluded from timing +- Output match compares against bash output when available +- Errors include execution failures and exit code mismatches +- In-process: interpreter runs inside the benchmark process +- Subprocess: new process spawned per benchmark run +- Persistent child: long-lived child process, amortizes startup cost + diff --git a/crates/bashkit/docs/threat-model.md b/crates/bashkit/docs/threat-model.md index e3ac30120..f44c2a411 100644 --- a/crates/bashkit/docs/threat-model.md +++ b/crates/bashkit/docs/threat-model.md @@ -99,6 +99,13 @@ through configurable limits. | find traversal amplification (TM-DOS-121) | `find -L` over a symlink cycle, unbounded `-exec ... {} +` batches, or `*`-heavy `-name` patterns | Canonical-path loop detection with a 40-hop symlink cap, budget-charged directory listings, capped output, batches flushed every 4096 paths, linear-time glob matching | MITIGATED | | Background job flooding (TM-DOS-122) | `while :; do sleep 99 & done` holds unbounded concurrent interpreters | `max_background_jobs` (64 default, 16 hardened) caps live jobs; extra `&` fails like bash's fork EAGAIN; jobs share the session budget, timeout and cancellation; every job is reaped when `exec()` returns | MITIGATED | +`join` matching-row products (TM-DOS-138) use shared-budget storage for +input decoding, parsed rows/fields/keys and generated output. Output growth and +its byte-stream copy are admitted before allocation. Parsing, key grouping and +each emitted field charge work and poll cancellation/deadlines, including +suppressed groups. Budget failures propagate as resource-limit errors. The +stdout capture limit remains downstream of pipelines and redirects. + **Parser and Arithmetic:** | Threat | Attack Example | Mitigation | Status | diff --git a/crates/bashkit/src/builtins/join.rs b/crates/bashkit/src/builtins/join.rs index 909c4c15c..c3b0a0a3d 100644 --- a/crates/bashkit/src/builtins/join.rs +++ b/crates/bashkit/src/builtins/join.rs @@ -4,12 +4,15 @@ //! blanks (leading blanks ignored) and output uses one space; with `-t C` //! every `C` separates and output uses `C`. Equal keys pair as a cartesian //! product. `-e` fills missing fields only where `-o` names them, as in GNU. +//! Decisions: generated output and parsed rows own shared-budget capacity; +//! scans and emissions charge work before copying, including suppressed rows. use async_trait::async_trait; use super::{Builtin, Context, resolve_path}; use crate::error::Result; use crate::interpreter::ExecResult; +use crate::limits::{BudgetedString, BudgetedVec, ExecutionBudget}; /// The join builtin command. /// @@ -148,148 +151,222 @@ impl Builtin for Join { return Ok(ExecResult::err("join: missing operand\n".to_string(), 1)); } - let content1 = read_input( - ctx.fs.as_ref(), - ctx.cwd, - files[0], - ctx.stdin.map(|stdin| &**stdin), - ) - .await?; - let content2 = read_input(ctx.fs.as_ref(), ctx.cwd, files[1], None).await?; - - Ok(ExecResult::ok(join_text(&opts, &content1, &content2))) + let budget = ctx + .execution_budget() + .map(|budget| { + budget + .try_with(Clone::clone) + .map_err(|_| crate::Error::Cancelled) + }) + .transpose()?; + let budget = budget.as_ref(); + let content1 = read_input(&ctx, files[0], ctx.stdin.map(|stdin| &**stdin), budget).await?; + let content2 = read_input(&ctx, files[1], None, budget).await?; + + let out = join_text(&opts, &content1, &content2, budget)?; + let (stdout, _storage) = crate::StreamData::from_budgeted_string(out, budget)?; + Ok(ExecResult::ok(stdout)) } } -fn split_fields(line: &str, sep: Option) -> Vec<&str> { - match sep { - Some(c) => line.split(c).collect(), - None => line.split([' ', '\t']).filter(|f| !f.is_empty()).collect(), +fn split_fields<'a>( + line: &'a str, + sep: Option, + budget: Option<&ExecutionBudget>, +) -> Result> { + let mut fields = BudgetedVec::new(budget)?; + for field in line.split(|c| sep.map_or(c == ' ' || c == '\t', |sep| c == sep)) { + work(budget, 1 + field.len() as u64)?; + if sep.is_some() || !field.is_empty() { + fields.try_push(field)?; + } } + Ok(fields) } struct Line<'a> { - fields: Vec<&'a str>, - key: String, + fields: BudgetedVec<&'a str>, + key: BudgetedString, } -fn parse_lines<'a>(text: &'a str, field: usize, opts: &JoinOptions) -> Vec> { - text.lines() - .map(|l| { - let fields = split_fields(l, opts.separator); - let key = fields.get(field - 1).copied().unwrap_or(""); - let key = if opts.ignore_case { - key.to_lowercase() - } else { - key.to_string() - }; - Line { fields, key } - }) - .collect() +fn work(budget: Option<&ExecutionBudget>, units: u64) -> Result<()> { + if let Some(budget) = budget { + budget.consume_work(units)?; + } + Ok(()) } -fn join_text(opts: &JoinOptions, text1: &str, text2: &str) -> String { - let mut lines1 = parse_lines(text1, opts.field1, opts); - let mut lines2 = parse_lines(text2, opts.field2, opts); +fn parse_lines<'a>( + text: &'a str, + field: usize, + opts: &JoinOptions, + budget: Option<&ExecutionBudget>, +) -> Result>> { + let mut lines = BudgetedVec::new(budget)?; + for line in text.lines() { + work(budget, 1)?; + let fields = split_fields(line, opts.separator, budget)?; + let source = fields.get(field - 1).copied().unwrap_or(""); + let mut key = BudgetedString::new(budget)?; + if opts.ignore_case { + // Preserve contextual Unicode lowercasing (for example final sigma). + // Unicode mapping expands by at most 3x; reserve another 2x for + // String's geometric growth and its minimum allocation capacity. + work(budget, 1 + source.len() as u64)?; + let capacity = source + .len() + .checked_mul(6) + .ok_or_else(|| crate::LimitExceeded::Memory("join: key size overflow".into()))? + .max(32); + let _lower_lease = budget.map(|b| b.lease_bytes(capacity)).transpose()?; + key = BudgetedString::try_from_string(source.to_lowercase(), budget)?; + } else { + key.try_push_str(source)?; + } + lines.try_push(Line { fields, key })?; + } + Ok(lines) +} + +// THREAT[TM-DOS-138]: admit every output append and poll synchronous join work. +fn join_text( + opts: &JoinOptions, + text1: &str, + text2: &str, + budget: Option<&ExecutionBudget>, +) -> Result { + let lines1 = parse_lines(text1, opts.field1, opts, budget)?; + let lines2 = parse_lines(text2, opts.field2, opts, budget)?; let out_sep = opts.separator.unwrap_or(' '); let fields = [opts.field1, opts.field2]; // `-o auto`: the join field, then every other field of each file's first line. - let format = opts.format.clone().or_else(|| { - opts.auto_format.then(|| { - let mut f = vec![OutField::Key]; - for (n, first) in [lines1.first(), lines2.first()].into_iter().enumerate() { - let count = first.map_or(0, |l| l.fields.len()); - f.extend( - (1..=count) - .filter(|&m| m != fields[n]) - .map(|m| OutField::Field(n + 1, m)), - ); + let mut auto_format = BudgetedVec::new(budget)?; + if opts.format.is_none() && opts.auto_format { + auto_format.try_push(OutField::Key)?; + for (n, first) in [lines1.first(), lines2.first()].into_iter().enumerate() { + let count = first.map_or(0, |l| l.fields.len()); + for m in 1..=count { + work(budget, 1)?; + if m != fields[n] { + auto_format.try_push(OutField::Field(n + 1, m))?; + } } - f - }) - }); - - let mut out = String::new(); - let emit = |out: &mut String, l1: Option<&Line>, l2: Option<&Line>| { + } + } + let format = opts + .format + .as_deref() + .or_else(|| opts.auto_format.then_some(&*auto_format)); + + let mut out = BudgetedString::new(budget)?; + let emit = |out: &mut BudgetedString, l1: Option<&Line>, l2: Option<&Line>| -> Result<()> { + work(budget, 1)?; let key = l1.or(l2).map_or("", |l| { let f = if l1.is_some() { fields[0] } else { fields[1] }; l.fields.get(f - 1).copied().unwrap_or("") }); - let mut parts: Vec<&str> = Vec::new(); + let mut first = true; + let mut append = |part: &str| -> Result<()> { + work(budget, 1 + part.len() as u64)?; + if !first { + out.try_push(out_sep)?; + } + first = false; + out.try_push_str(part)?; + Ok(()) + }; let empty = opts.empty.as_deref().unwrap_or(""); - match &format { + match format { Some(format) => { for item in format { - parts.push(match *item { + append(match *item { OutField::Key => key, OutField::Field(n, m) => { let side = if n == 1 { l1 } else { l2 }; side.and_then(|l| l.fields.get(m - 1).copied()) .unwrap_or(empty) } - }); + })?; } } None => { - parts.push(key); + append(key)?; for (n, side) in [l1, l2].into_iter().enumerate() { if let Some(l) = side { - parts.extend( - l.fields - .iter() - .enumerate() - .filter(|(i, _)| *i + 1 != fields[n]) - .map(|(_, f)| *f), - ); + for (i, field) in l.fields.iter().enumerate() { + if i + 1 != fields[n] { + append(field)?; + } + } } } } } - for (i, p) in parts.iter().enumerate() { - if i > 0 { - out.push(out_sep); - } - out.push_str(p); - } - out.push('\n'); + out.try_push('\n')?; + Ok(()) }; if opts.header { - let h1 = (!lines1.is_empty()).then(|| lines1.remove(0)); - let h2 = (!lines2.is_empty()).then(|| lines2.remove(0)); + let h1 = lines1.first(); + let h2 = lines2.first(); if h1.is_some() || h2.is_some() { - emit(&mut out, h1.as_ref(), h2.as_ref()); + emit(&mut out, h1, h2)?; } } - let (mut i, mut j) = (0, 0); + let (mut i, mut j) = if opts.header { + ( + usize::from(!lines1.is_empty()), + usize::from(!lines2.is_empty()), + ) + } else { + (0, 0) + }; while i < lines1.len() || j < lines2.len() { + work(budget, 1)?; let ord = match (lines1.get(i), lines2.get(j)) { - (Some(a), Some(b)) => a.key.cmp(&b.key), + (Some(a), Some(b)) => { + work(budget, 1 + a.key.len().min(b.key.len()) as u64)?; + (*a.key).cmp(&*b.key) + } (Some(_), None) => std::cmp::Ordering::Less, _ => std::cmp::Ordering::Greater, }; match ord { std::cmp::Ordering::Less => { if opts.unpaired[0] { - emit(&mut out, Some(&lines1[i]), None); + emit(&mut out, Some(&lines1[i]), None)?; } i += 1; } std::cmp::Ordering::Greater => { if opts.unpaired[1] { - emit(&mut out, None, Some(&lines2[j])); + emit(&mut out, None, Some(&lines2[j]))?; } j += 1; } std::cmp::Ordering::Equal => { - let key = lines1[i].key.clone(); - let end1 = i + lines1[i..].iter().take_while(|l| l.key == key).count(); - let end2 = j + lines2[j..].iter().take_while(|l| l.key == key).count(); + let key = &*lines1[i].key; + let mut end1 = i; + while end1 < lines1.len() { + work(budget, 1 + key.len().min(lines1[end1].key.len()) as u64)?; + if &*lines1[end1].key != key { + break; + } + end1 += 1; + } + let mut end2 = j; + while end2 < lines2.len() { + work(budget, 1 + key.len().min(lines2[end2].key.len()) as u64)?; + if &*lines2[end2].key != key { + break; + } + end2 += 1; + } if !opts.only_unpaired { for a in &lines1[i..end1] { for b in &lines2[j..end2] { - emit(&mut out, Some(a), Some(b)); + emit(&mut out, Some(a), Some(b))?; } } } @@ -298,7 +375,7 @@ fn join_text(opts: &JoinOptions, text1: &str, text2: &str) -> String { } } } - out + Ok(out) } fn parse_field_number(option: &str, value: &str) -> std::result::Result { @@ -310,18 +387,34 @@ fn parse_field_number(option: &str, value: &str) -> std::result::Result, file: &str, stdin: Option<&str>, -) -> Result { + budget: Option<&ExecutionBudget>, +) -> Result { + let mut text = BudgetedString::new(budget)?; if file == "-" { - Ok(stdin.unwrap_or("").to_string()) + let stdin = stdin.unwrap_or(""); + work(budget, 1 + stdin.len() as u64)?; + text.try_push_str(stdin)?; } else { - let path = resolve_path(cwd, file); - let bytes = fs.read_file(&path).await?; - Ok(String::from_utf8_lossy(&bytes).to_string()) + let path = resolve_path(ctx.cwd, file); + let size = usize::try_from(ctx.fs.stat(&path).await?.size) + .map_err(|_| crate::LimitExceeded::Memory("join: input size overflow".into()))?; + ctx.consume_budget_input(size)?; + let _read_lease = ctx.lease_budget_bytes(size)?; + let bytes = ctx.fs.read_file(&path).await?; + ctx.consume_budget_input(bytes.len().saturating_sub(size))?; + let _extra_lease = ctx.lease_budget_bytes(bytes.capacity().saturating_sub(size))?; + for chunk in bytes.utf8_chunks() { + work(budget, 1 + chunk.valid().len() as u64)?; + text.try_push_str(chunk.valid())?; + if !chunk.invalid().is_empty() { + text.try_push('\u{fffd}')?; + } + } } + Ok(text) } #[cfg(test)] @@ -332,6 +425,70 @@ mod tests { use std::path::{Path, PathBuf}; use std::sync::Arc; + fn options() -> JoinOptions { + JoinOptions { + field1: 1, + field2: 1, + separator: None, + unpaired: [false; 2], + only_unpaired: false, + empty: None, + format: None, + auto_format: false, + ignore_case: false, + header: false, + } + } + + #[test] + fn ordinary_join_output_growth_requires_admission() { + // Parsed storage fits; the final output capacity growth does not. + let parsed = 4 * std::mem::size_of::() + 8 * std::mem::size_of::<&str>() + 4; + let budget = ExecutionBudget::new( + &crate::ExecutionLimits::new().max_live_intermediate_bytes((parsed + 23) as u64), + Arc::new(std::sync::atomic::AtomicBool::new(false)), + ); + let error = join_text(&options(), "a 1\na 2\n", "a x\na y\n", Some(&budget)).unwrap_err(); + assert!(error.to_string().contains("live intermediate"), "{error}"); + } + + #[test] + fn ordinary_join_preserves_contextual_unicode_lowercasing() { + let mut opts = options(); + opts.ignore_case = true; + let out = join_text(&opts, "ΟΣ 1\n", "ος x\n", None).unwrap(); + assert_eq!(&*out, "ΟΣ 1 x\n"); + } + + #[test] + fn ordinary_join_emissions_consume_work() { + let budget = ExecutionBudget::new( + &crate::ExecutionLimits::new().max_work_units(40), + Arc::new(std::sync::atomic::AtomicBool::new(false)), + ); + let error = join_text(&options(), "a 1\na 2\n", "a x\na y\n", Some(&budget)).unwrap_err(); + assert!(error.to_string().contains("work units"), "{error}"); + } + + #[test] + fn ordinary_join_polls_cancelled_and_expired_budgets() { + let cancelled = Arc::new(std::sync::atomic::AtomicBool::new(false)); + let budget = ExecutionBudget::new(&crate::ExecutionLimits::new(), cancelled.clone()); + cancelled.store(true, std::sync::atomic::Ordering::Relaxed); + let error = join_text(&options(), "a 1\n", "a x\n", Some(&budget)).unwrap_err(); + assert!(error.to_string().contains("cancel"), "{error}"); + let budget = ExecutionBudget::new( + &crate::ExecutionLimits::new().timeout(std::time::Duration::ZERO), + Arc::new(std::sync::atomic::AtomicBool::new(false)), + ); + std::thread::sleep(std::time::Duration::from_millis(120)); + let error = join_text(&options(), "a 1\n", "a x\n", Some(&budget)).unwrap_err(); + assert!(matches!( + error, + crate::Error::ResourceLimit(crate::LimitExceeded::Timeout(_)) + )); + } + async fn run_join(args: &[&str], fs: Arc) -> ExecResult { let args: Vec = args.iter().map(|s| s.to_string()).collect(); let env = HashMap::new(); diff --git a/crates/bashkit/src/stream.rs b/crates/bashkit/src/stream.rs index e22fb3799..928a3929d 100644 --- a/crates/bashkit/src/stream.rs +++ b/crates/bashkit/src/stream.rs @@ -17,6 +17,21 @@ pub struct StreamData { } impl StreamData { + /// Convert admitted text to the byte/text stream without an uncharged copy. + pub(crate) fn from_budgeted_string( + text: crate::limits::BudgetedString, + budget: Option<&crate::limits::ExecutionBudget>, + ) -> Result<(Self, StreamStorage), crate::limits::LimitExceeded> { + let mut bytes = crate::limits::BudgetedBytes::new(budget)?; + if let Some(budget) = budget { + budget.consume_work(1 + text.len() as u64)?; + } + bytes.try_extend_from_slice(text.as_bytes())?; + let (bytes, byte_storage) = bytes.into_parts(); + let (text, text_storage) = text.into_parts(); + Ok((Self { bytes, text }, [byte_storage, text_storage])) + } + /// Materialize cached text without releasing the byte buffer's lease or /// allocating a temporary lossy string outside the request budget. // THREAT[TM-DOS-103]: both representations must be admitted before growth. @@ -205,6 +220,33 @@ impl serde::Serialize for StreamData { mod tests { use super::StreamData; + #[test] + fn budgeted_string_stream_admits_both_representations() { + for limit in [7, 8] { + let budget = crate::limits::ExecutionBudget::new( + &crate::ExecutionLimits::new().max_live_intermediate_bytes(limit), + std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), + ); + let mut text = crate::limits::BudgetedString::new(Some(&budget)).unwrap(); + text.try_push_str("text").unwrap(); + let result = StreamData::from_budgeted_string(text, Some(&budget)); + if limit == 7 { + assert!( + result + .unwrap_err() + .to_string() + .contains("live intermediate") + ); + } else { + let (stream, storage) = result.unwrap(); + assert_eq!(stream.as_bytes(), b"text"); + assert_eq!(stream.text_lossy(), "text"); + assert!(budget.lease_bytes(1).is_err()); + drop(storage); + } + } + } + #[test] fn budgeted_text_preserves_bytes_and_lossy_decoding() { for input in [ diff --git a/crates/bashkit/tests/integration/join_resource_tests.rs b/crates/bashkit/tests/integration/join_resource_tests.rs new file mode 100644 index 000000000..bab9295f4 --- /dev/null +++ b/crates/bashkit/tests/integration/join_resource_tests.rs @@ -0,0 +1,137 @@ +//! Ordinary join rows exercise configured budgets through the public API. +use bashkit::{Bash, Error, ExecutionLimits, LimitExceeded}; +use std::path::Path; + +async fn two_tables(limits: ExecutionLimits) -> Bash { + let bash = Bash::builder().limits(limits).build(); + bash.fs() + .write_file(Path::new("/left"), b"a 1\na 2\n") + .await + .unwrap(); + bash.fs() + .write_file(Path::new("/right"), b"a x\na y\n") + .await + .unwrap(); + bash +} + +#[tokio::test] +async fn join_ordinary_rows_charge_generated_work() { + let mut bash = two_tables(ExecutionLimits::new().max_work_units(70)).await; + let result = bash.exec("join /left /right").await; + assert!( + matches!( + result, + Err(Error::ResourceLimit(LimitExceeded::ExecutionBudget(_))) + ), + "{result:?}" + ); + assert!(result.unwrap_err().to_string().contains("work units")); + assert_eq!( + bash.exec("echo recovered").await.unwrap().stdout, + "recovered\n" + ); +} + +#[tokio::test] +async fn join_ordinary_cartesian_rows_survive_pipe_and_redirect() { + let mut bash = two_tables(ExecutionLimits::new().max_stdout_bytes(8)).await; + let expected = b"a 1 x\na 1 y\na 2 x\na 2 y\n"; + assert_eq!( + bash.exec("join /left /right | wc -c") + .await + .unwrap() + .stdout + .trim(), + "24" + ); + assert_eq!( + bash.exec("join /left /right > /joined") + .await + .unwrap() + .exit_code, + 0 + ); + assert_eq!( + bash.fs().read_file(Path::new("/joined")).await.unwrap(), + expected + ); +} + +#[tokio::test] +async fn join_ordinary_input_and_memory_limits_recover() { + for limits in [ + ExecutionLimits::new().max_aggregate_input_bytes(7), + ExecutionLimits::new().max_live_intermediate_bytes(512), + ] { + let mut bash = two_tables(limits).await; + let result = bash.exec("join /left /right").await; + assert!( + matches!( + result, + Err(Error::ResourceLimit(LimitExceeded::ExecutionBudget(_))) + ), + "{result:?}" + ); + assert_eq!(bash.exec("echo x").await.unwrap().stdout, "x\n"); + } +} + +#[tokio::test] +async fn join_ordinary_options_match_gnu() { + let program = if Path::new("/opt/homebrew/bin/gjoin").is_file() { + "/opt/homebrew/bin/gjoin" + } else { + "join" + }; + let version = std::process::Command::new(program) + .arg("--version") + .output() + .unwrap(); + let is_gnu = String::from_utf8_lossy(&version.stdout).contains("GNU coreutils"); + #[cfg(target_os = "linux")] + assert!(is_gnu, "GNU join is required by Linux CI"); + if !is_gnu { + return; + } + let dir = tempfile::tempdir().unwrap(); + let left = dir.path().join("left"); + let right = dir.path().join("right"); + for (a, b, flags) in [ + ("a 1\na 2\n", "a x\na y\n", ""), + ("a 1\nb 2\n", "a x\nc y\n", "-a 1 -a 2 -e NA -o 0,1.2,2.2"), + ("a 1\nb 2\n", "a x\nc y\n", "-v 1"), + ("id name\na 1\n", "id value\na x\n", "--header -o auto"), + ("A:1\nB:2\n", "a:x\nb:y\n", "-i -t : -o 1.2,0,2.2"), + ] { + std::fs::write(&left, a).unwrap(); + std::fs::write(&right, b).unwrap(); + let oracle = std::process::Command::new(program) + .args(flags.split_whitespace()) + .arg(&left) + .arg(&right) + .output() + .unwrap(); + assert!( + oracle.status.success(), + "{}", + String::from_utf8_lossy(&oracle.stderr) + ); + let mut bash = Bash::new(); + bash.fs() + .write_file(Path::new("/left"), a.as_bytes()) + .await + .unwrap(); + bash.fs() + .write_file(Path::new("/right"), b.as_bytes()) + .await + .unwrap(); + let actual = bash + .exec(&format!("join {flags} /left /right")) + .await + .unwrap(); + assert_eq!(actual.exit_code, 0); + assert_eq!(actual.stdout.as_bytes(), oracle.stdout, "flags={flags}"); + assert_eq!(actual.stderr.as_bytes(), oracle.stderr, "flags={flags}"); + } +} diff --git a/crates/bashkit/tests/integration/main.rs b/crates/bashkit/tests/integration/main.rs index cc0bb3643..69640799a 100644 --- a/crates/bashkit/tests/integration/main.rs +++ b/crates/bashkit/tests/integration/main.rs @@ -110,6 +110,7 @@ pub mod issue_853_test; pub mod issue_872_test; pub mod issue_873_test; pub mod issue_875_test; +pub mod join_resource_tests; pub mod jq_fuzz_scaffold_tests; pub mod limitations_doc_tests; pub mod limitations_evidence_tests; diff --git a/docs/security.md b/docs/security.md index 3f5264d06..3b0f37f99 100644 --- a/docs/security.md +++ b/docs/security.md @@ -50,6 +50,14 @@ deadlines. Exceeding a budget returns a resource-limit error. Output within the budget preserves its formatting through pipelines and file redirects, even when it exceeds the stdout capture limit. +`join` preserves matching-row Cartesian products within the execution budget. +Input rows, keys and generated output reserve live-memory capacity before +allocation. Parsing, key grouping and every emitted field consume shared work +and check cancellation and deadlines. Budget failures abort the request with a +resource-limit error; a later host execution starts with a fresh budget. Stdout +capture limits remain downstream, so pipelines and redirects receive complete +join output when it fits the execution budget. + `cd` searches `CDPATH` one candidate at a time. Temporary path and normalization storage is reserved against `max_live_intermediate_bytes` before allocation. Searches also consume the shared work budget and check diff --git a/knowledge/foundations/builtins.md b/knowledge/foundations/builtins.md index c5a0e32e4..d984080f6 100644 --- a/knowledge/foundations/builtins.md +++ b/knowledge/foundations/builtins.md @@ -635,6 +635,22 @@ failures, never successful partial output. The stdout capture ceiling does not limit a formatter sink used by a pipeline or VFS redirect. Regression coverage: `fmt_resource_tests` and the formatter's capacity/cancellation/deadline unit tests. +### join + +`join` preserves GNU matching-row Cartesian products, field selection, +unpaired rows, headers and contextual Unicode case folding. Parsed row/field +vectors, keys, input decoding and output use shared-budget storage; generated +fields append directly without a temporary per-row vector. Input metadata +admits VFS reads, actual capacity growth is charged, and repeated file reads +share aggregate-input accounting. Parsing, grouping (including `-v` suppressed +groups), comparisons and emissions charge work and check cancellation/deadlines. +Output text and its byte-stream copy both require admission before allocation. +Failures propagate through the Bash API as resource-limit errors. Capture caps +remain downstream so pipelines and redirects preserve complete admitted output. +Regression fixtures use at most two rows per input and small configured budgets: +`join_resource_tests`, `builtins::join::tests::ordinary_join_*`, and +`stream::tests::budgeted_string_stream_admits_both_representations` (TM-DOS-138). + ### Network Builtins `curl`, `wget`, `http` require the `http_client` feature + URL allowlist. diff --git a/knowledge/security/threat-model.md b/knowledge/security/threat-model.md index e1cbd07fd..c474a41f3 100644 --- a/knowledge/security/threat-model.md +++ b/knowledge/security/threat-model.md @@ -311,6 +311,8 @@ on default 2 MiB test threads (TM-DOS-044). | TM-DOS-135 | Indirect array-target operand recursion | `r='a[0]:-${!r}]'; echo "${!r}"`: the bracket validator accepted trailing operator/nesting text, so desugar re-parsed `${a[0]:-${!r}]}` and the unset-element default re-entered indirect expansion without bound (stack overflow). Numbered to avoid collision with the adjacent tilde-budget entry | A bracket target is valid only when the first complete `[...]` reference (nesting- and quote-aware) consumes the whole value; any trailing text is refused with `invalid variable name`, like modern bash 5.x (older 3.2 ignored the tail). Refusal keeps a nested `${!...}` from ever reaching the desugar re-parse while valid nested subscripts (`a[b[0]]`) resolve whole; `$(`/backquote/process-substitution guards unchanged. Regressions: `indirect_array_boundary_rejects_trailing_operators`, `indirect_hostile_cycles_rejected_in_bounded_child`, `indirect_nested_indexed_matches_real_bash` | **MITIGATED** | | TM-DOS-137 | pr pagination amplification | A long `-h` title repeated once per empty line with `-l 11` grows gigabytes before a late output check; eager `-D` date copies amplify across retained inputs | Each row/output append checks the 16 MiB cap before growth; header parts append directly without a temporary title copy. Inputs retain date timestamps, formatting dates one nonempty stream at a time. Input lines, cells, rows and output lease capacity before allocation; cells borrow input text and pages borrow row slices. Input/row/page loops charge shared work, input bytes charge aggregate input, and budgeted growth polls cancellation/deadlines. Regressions: `pr_resource_tests`, cap/UTF-8/cancellation unit tests and `pr_allocation_tests` peak-heap bound | **MITIGATED** | | TM-DOS-107 | Static-analysis command validation amplification | A large comment before thousands of commands makes a whole-script ordered-subsequence scan per command | Build one source-character position index, then validate each analyzed command-name character with a logarithmic position lookup instead of rescanning source | **MITIGATED** | +| TM-DOS-138 | Join matching-row output growth | Equal-key row groups multiply generated output and synchronous work before dispatcher capture | Parsed rows, fields, keys, decoded input and generated output own shared-budget capacity before growth. VFS reads charge aggregate input and admit metadata size; output fields append directly without temporary row storage, and the byte-stream copy is admitted. Parsing, grouping (including suppressed matches), comparisons and emissions charge work and poll cancellation/deadlines. Errors abort the request. Ordinary two-row fixtures cover memory/work rejection, cancellation/deadlines, session recovery, and complete pipeline/redirect output | **MITIGATED** | + **TM-DOS-051** is historical. The custom parser was deleted with the `yaml` helper; the replacement `yq` parser/evaluator boundary is tracked by TM-DOS-101. diff --git a/site/src/data/performance-timeline.json b/site/src/data/performance-timeline.json index 5d9180bcd..f68a71df8 100644 --- a/site/src/data/performance-timeline.json +++ b/site/src/data/performance-timeline.json @@ -1,5 +1,5 @@ { - "generatedAt": "2026-10-13T02:14:50.000Z", + "generatedAt": "2026-10-13T04:29:43.000Z", "sources": { "bench": "crates/bashkit-bench/results/*.json", "criterion": "crates/bashkit/benches/results/*.md", @@ -8,21 +8,21 @@ "oilsSpec": "scripts/oils-spec/results/oils-spec-*.json" }, "summary": { - "benchRuns": 11, + "benchRuns": 12, "criterionRuns": 18, "evalRuns": 57, "latestBench": { - "id": "bench-mykhailosmin-macos-aarch64-1791857690", + "id": "bench-mykhailosmin-macos-aarch64-1791865783", "kind": "bashkit-bench", "label": "mykhailosmin-macos-aarch64", "date": "2026-10-13", - "timestamp": "2026-10-13T02:14:50.000Z", - "source": "crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791857690.json", - "reportSource": "crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791857690.md", + "timestamp": "2026-10-13T04:29:43.000Z", + "source": "crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.json", + "reportSource": "crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.md", "cases": 96, - "speedup": 58.1, - "bashkitMs": 27.91, - "bashMs": 1622.93, + "speedup": 23.9, + "bashkitMs": 103.2, + "bashMs": 2463.28, "errorRate": 0, "matchRate": 100, "categories": [ @@ -31,96 +31,96 @@ "description": "Small commands where interpreter startup dominates runtime.", "cases": 4, "bashkitMedianMs": 0.031, - "bashMedianMs": 7.72, - "speedup": 241.3 + "bashMedianMs": 4.784, + "speedup": 155.1 }, { "category": "arithmetic", "description": "Integer math, substitutions, and expression-heavy shell snippets.", "cases": 6, "bashkitMedianMs": 0.034, - "bashMedianMs": 6.172, - "speedup": 184 + "bashMedianMs": 4.785, + "speedup": 140.1 }, { "category": "variables", "description": "Variable assignment, lookup, expansion, and environment handling.", "cases": 8, "bashkitMedianMs": 0.035, - "bashMedianMs": 5.948, - "speedup": 169 + "bashMedianMs": 4.499, + "speedup": 133.7 }, { - "category": "strings", - "description": "String expansion, pattern handling, and text manipulation.", - "cases": 8, - "bashkitMedianMs": 0.039, - "bashMedianMs": 8.12, - "speedup": 186.4 + "category": "arrays", + "description": "Indexed array reads, writes, expansion, and iteration.", + "cases": 6, + "bashkitMedianMs": 0.04, + "bashMedianMs": 7.029, + "speedup": 176.5 }, { "category": "pipes", "description": "Pipeline construction, streaming, and command chaining.", "cases": 6, - "bashkitMedianMs": 0.041, - "bashMedianMs": 7.873, - "speedup": 175 - }, - { - "category": "control", - "description": "Conditionals, loops, case statements, and branching scripts.", - "cases": 9, - "bashkitMedianMs": 0.047, - "bashMedianMs": 9.903, - "speedup": 169.5 - }, - { - "category": "subshell", - "description": "Command substitution and nested shell execution paths.", - "cases": 6, - "bashkitMedianMs": 0.048, - "bashMedianMs": 8.437, - "speedup": 180.4 + "bashkitMedianMs": 0.043, + "bashMedianMs": 8.666, + "speedup": 200.8 }, { "category": "io", "description": "File reads, writes, redirects, and filesystem-facing commands.", "cases": 6, - "bashkitMedianMs": 0.052, - "bashMedianMs": 6.803, - "speedup": 155.8 + "bashkitMedianMs": 0.048, + "bashMedianMs": 6.544, + "speedup": 149.7 }, { "category": "tools", "description": "Builtin and external-tool style command workloads.", "cases": 21, - "bashkitMedianMs": 0.055, - "bashMedianMs": 8.689, - "speedup": 176.4 + "bashkitMedianMs": 0.049, + "bashMedianMs": 10.236, + "speedup": 197.1 }, { - "category": "arrays", - "description": "Indexed array reads, writes, expansion, and iteration.", + "category": "subshell", + "description": "Command substitution and nested shell execution paths.", "cases": 6, - "bashkitMedianMs": 0.057, - "bashMedianMs": 7.128, - "speedup": 142.6 + "bashkitMedianMs": 0.049, + "bashMedianMs": 8.872, + "speedup": 160.5 + }, + { + "category": "control", + "description": "Conditionals, loops, case statements, and branching scripts.", + "cases": 9, + "bashkitMedianMs": 0.055, + "bashMedianMs": 7.842, + "speedup": 167.3 + }, + { + "category": "strings", + "description": "String expansion, pattern handling, and text manipulation.", + "cases": 8, + "bashkitMedianMs": 0.07, + "bashMedianMs": 8.768, + "speedup": 152.8 }, { "category": "complex", "description": "Mixed shell workflows that combine multiple language features.", "cases": 7, - "bashkitMedianMs": 0.09, - "bashMedianMs": 8.652, - "speedup": 66.5 + "bashkitMedianMs": 0.108, + "bashMedianMs": 9.608, + "speedup": 71.7 }, { "category": "large", "description": "Bigger scripts and higher-volume data paths.", "cases": 9, - "bashkitMedianMs": 1.091, - "bashMedianMs": 7.415, - "speedup": 23.2 + "bashkitMedianMs": 1.016, + "bashMedianMs": 7.134, + "speedup": 16 } ] }, @@ -1716,6 +1716,119 @@ "speedup": 23.2 } ] + }, + { + "id": "bench-mykhailosmin-macos-aarch64-1791865783", + "kind": "bashkit-bench", + "label": "mykhailosmin-macos-aarch64", + "date": "2026-10-13", + "timestamp": "2026-10-13T04:29:43.000Z", + "source": "crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.json", + "reportSource": "crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.md", + "cases": 96, + "speedup": 23.9, + "bashkitMs": 103.2, + "bashMs": 2463.28, + "errorRate": 0, + "matchRate": 100, + "categories": [ + { + "category": "startup", + "description": "Small commands where interpreter startup dominates runtime.", + "cases": 4, + "bashkitMedianMs": 0.031, + "bashMedianMs": 4.784, + "speedup": 155.1 + }, + { + "category": "arithmetic", + "description": "Integer math, substitutions, and expression-heavy shell snippets.", + "cases": 6, + "bashkitMedianMs": 0.034, + "bashMedianMs": 4.785, + "speedup": 140.1 + }, + { + "category": "variables", + "description": "Variable assignment, lookup, expansion, and environment handling.", + "cases": 8, + "bashkitMedianMs": 0.035, + "bashMedianMs": 4.499, + "speedup": 133.7 + }, + { + "category": "arrays", + "description": "Indexed array reads, writes, expansion, and iteration.", + "cases": 6, + "bashkitMedianMs": 0.04, + "bashMedianMs": 7.029, + "speedup": 176.5 + }, + { + "category": "pipes", + "description": "Pipeline construction, streaming, and command chaining.", + "cases": 6, + "bashkitMedianMs": 0.043, + "bashMedianMs": 8.666, + "speedup": 200.8 + }, + { + "category": "io", + "description": "File reads, writes, redirects, and filesystem-facing commands.", + "cases": 6, + "bashkitMedianMs": 0.048, + "bashMedianMs": 6.544, + "speedup": 149.7 + }, + { + "category": "tools", + "description": "Builtin and external-tool style command workloads.", + "cases": 21, + "bashkitMedianMs": 0.049, + "bashMedianMs": 10.236, + "speedup": 197.1 + }, + { + "category": "subshell", + "description": "Command substitution and nested shell execution paths.", + "cases": 6, + "bashkitMedianMs": 0.049, + "bashMedianMs": 8.872, + "speedup": 160.5 + }, + { + "category": "control", + "description": "Conditionals, loops, case statements, and branching scripts.", + "cases": 9, + "bashkitMedianMs": 0.055, + "bashMedianMs": 7.842, + "speedup": 167.3 + }, + { + "category": "strings", + "description": "String expansion, pattern handling, and text manipulation.", + "cases": 8, + "bashkitMedianMs": 0.07, + "bashMedianMs": 8.768, + "speedup": 152.8 + }, + { + "category": "complex", + "description": "Mixed shell workflows that combine multiple language features.", + "cases": 7, + "bashkitMedianMs": 0.108, + "bashMedianMs": 9.608, + "speedup": 71.7 + }, + { + "category": "large", + "description": "Bigger scripts and higher-volume data paths.", + "cases": 9, + "bashkitMedianMs": 1.016, + "bashMedianMs": 7.134, + "speedup": 16 + } + ] } ], "criterionRuns": [ @@ -9596,6 +9709,15 @@ "detail": "96 parity/perf cases on mykhailosmin-macos-aarch64; output match 100%.", "metric": 58.1, "source": "crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791857690.json" + }, + { + "date": "2026-10-13", + "timestamp": "2026-10-13T04:29:43.000Z", + "kind": "Benchmark", + "title": "23.9x faster than bash", + "detail": "96 parity/perf cases on mykhailosmin-macos-aarch64; output match 100%.", + "metric": 23.9, + "source": "crates/bashkit-bench/results/bench-mykhailosmin-macos-aarch64-1791865783.json" } ] }