Add Recipemanager that loads recipes from YAML

This commit is contained in:
JonShard
2026-07-17 13:54:14 +02:00
parent 840908e9ff
commit 4d06e72bc1
133 changed files with 9121 additions and 175 deletions
@@ -0,0 +1,283 @@
extends ExampleBase
## Number of iterations for each benchmark
const ITERATIONS: int = 10
## Thread counts for multithreaded benchmarks
const THREAD_COUNTS: Array = [1, 2, 4, 8, 16, 32, 64, 100]
## Path to the YAML file to benchmark
const YAML_PATH: String = "res://addons/yaml/examples/data/supported_syntax.yaml"
func _init() -> void:
icon = ""
func run_examples() -> void:
log_header("YAML Speed Benchmark")
print(YAML.version())
run_example("Load YAML File", load_yaml_file_benchmark)
run_example("Parse (No Style) Benchmark", parse_benchmark)
run_example("Parse (With Style) Benchmark", parse_with_style_benchmark)
run_example("Stringify (No Style) Benchmark", stringify_benchmark)
run_example("Stringify (With Style) Benchmark", stringify_with_style_benchmark)
run_example("Compare Results", compare_results)
run_example("Parse (Threaded) Bechmark", parse_threaded)
run_example("Stringify (Threaded) Benchmark", stringify_threaded)
var yaml_input: String
var parse_times := []
var style_parse_times := []
var stringify_times := []
var style_stringify_times := []
var data = null
var style = null
func load_yaml_file_benchmark() -> void:
log_info("Loading YAML file: " + YAML_PATH)
var file := FileAccess.open(YAML_PATH, FileAccess.READ)
if !file:
log_error("Could not open file: " + YAML_PATH)
return
yaml_input = file.get_as_text()
log_success("File loaded, size: " + str(yaml_input.length()) + " characters")
var result := YAML.parse(yaml_input)
data = result.get_data()
if LOG_VERBOSE:
log_result("First 200 characters:\n" + yaml_input.substr(0, 200) + "...")
func parse_benchmark() -> void:
if yaml_input.is_empty():
log_error("No YAML input loaded")
return
log_info("Running parse benchmark (" + str(ITERATIONS) + " iterations)...")
for i in range(ITERATIONS):
var start := Time.get_ticks_usec()
var result = YAML.parse(yaml_input)
var elapsed := Time.get_ticks_usec() - start
if result.has_error():
log_error("Iteration " + str(i + 1) + " failed: " + result.get_error())
continue
parse_times.append(elapsed)
log_info("Iteration " + str(i + 1) + ": " + str(elapsed) + " µs")
if parse_times.size() > 0:
var avg = float(parse_times.reduce(func(a, b): return a + b)) / parse_times.size()
log_success("Average parse time: " + str(avg) + " µs")
else:
log_error("No successful parse iterations")
func parse_with_style_benchmark() -> void:
if yaml_input.is_empty():
log_error("No YAML input loaded")
return
log_info("Running parse with style benchmark (" + str(ITERATIONS) + " iterations)...")
for i in range(ITERATIONS):
var start := Time.get_ticks_usec()
var result = YAML.parse(yaml_input, YAML.create_security(), true)
var elapsed := Time.get_ticks_usec() - start
if result.has_error():
log_error("Iteration " + str(i + 1) + " failed: " + result.get_error())
continue
if i == 0:
style = result.get_style()
style_parse_times.append(elapsed)
log_info("Iteration " + str(i + 1) + ": " + str(elapsed) + " µs")
if style_parse_times.size() > 0:
var avg = float(style_parse_times.reduce(func(a, b): return a + b)) / style_parse_times.size()
log_success("Average parse with style time: " + str(avg) + " µs")
else:
log_error("No successful parse with style iterations")
func stringify_benchmark() -> void:
if data == null:
log_error("No data available for stringify tests")
return
log_info("Running stringify benchmark (" + str(ITERATIONS) + " iterations)...")
for i in range(ITERATIONS):
var start := Time.get_ticks_usec()
var result = YAML.stringify(data)
var elapsed := Time.get_ticks_usec() - start
if result.has_error():
log_error("Iteration " + str(i + 1) + " failed: " + result.get_error())
continue
stringify_times.append(elapsed)
log_info("Iteration " + str(i + 1) + ": " + str(elapsed) + " µs")
if stringify_times.size() > 0:
var avg = float(stringify_times.reduce(func(a, b): return a + b)) / stringify_times.size()
log_success("Average stringify time: " + str(avg) + " µs")
else:
log_error("No successful stringify iterations")
func stringify_with_style_benchmark() -> void:
if data == null or style == null:
log_error("No data or style available for stringify tests")
return
log_info("Running stringify with style benchmark (" + str(ITERATIONS) + " iterations)...")
for i in range(ITERATIONS):
var start := Time.get_ticks_usec()
var result = YAML.stringify(data, style)
var elapsed := Time.get_ticks_usec() - start
if result.has_error():
log_error("Iteration " + str(i + 1) + " failed: " + result.get_error())
continue
style_stringify_times.append(elapsed)
log_info("Iteration " + str(i + 1) + ": " + str(elapsed) + " µs")
if style_stringify_times.size() > 0:
var avg = float(style_stringify_times.reduce(func(a, b): return a + b)) / style_stringify_times.size()
log_success("Average stringify with style time: " + str(avg) + " µs")
else:
log_error("No successful stringify with style iterations")
func compare_results() -> void:
log_subheader("Performance Comparison")
# Collect all test results
var all_tests = [
{
"name": "Parse (no style)",
"times": parse_times
},
{
"name": "Parse (with style)",
"times": style_parse_times
},
{
"name": "Stringify (no style)",
"times": stringify_times
},
{
"name": "Stringify (with style)",
"times": style_stringify_times
}
]
# Calculate and print stats
for test in all_tests:
var times = test.times
if times.is_empty():
log_warning(test.name + ": No valid results")
continue
var avg: float = float(times.reduce(func(a, b): return a + b)) / times.size()
var min_time: int = times.min()
var max_time: int = times.max()
log_info(test.name + ":")
log_info(" Average: %.2f µs" % avg)
log_info(" Min: %d µs" % min_time)
log_info(" Max: %d µs" % max_time)
log_info("\nPerformance Insights:")
# Compare parse with and without style
if !parse_times.is_empty() and !style_parse_times.is_empty():
var avg_parse = float(parse_times.reduce(func(a, b): return a + b)) / parse_times.size()
var avg_style_parse = float(style_parse_times.reduce(func(a, b): return a + b)) / style_parse_times.size()
var style_overhead = ((avg_style_parse / avg_parse) - 1.0) * 100.0
log_info("Style detection adds approximately %.1f%% overhead to parsing" % style_overhead)
# Compare stringify with and without style
if !stringify_times.is_empty() and !style_stringify_times.is_empty():
var avg_stringify = float(stringify_times.reduce(func(a, b): return a + b)) / stringify_times.size()
var avg_style_stringify = float(style_stringify_times.reduce(func(a, b): return a + b)) / style_stringify_times.size()
var style_overhead = ((avg_style_stringify / avg_stringify) - 1.0) * 100.0
log_info("Using style adds approximately %.1f%% overhead to stringify" % style_overhead)
func parse_threaded() -> void:
if yaml_input.is_empty():
log_error("No YAML input loaded")
return
log_subheader("Threaded Parse Benchmark")
for thread_count in THREAD_COUNTS:
var threads: Array[Thread] = []
var start := Time.get_ticks_usec()
for i in range(thread_count):
var thread := Thread.new()
thread.start(_parse_thread_func.bind(yaml_input))
threads.append(thread)
var total_parse_time := 0
for thread in threads:
total_parse_time += thread.wait_to_finish()
var wall_time := Time.get_ticks_usec() - start
var avg_thread_time := float(total_parse_time / thread_count)
log_info("%d thread(s): wall=%d µs | avg thread=%d µs | throughput=%.1f parses/ms" % [
thread_count,
wall_time,
avg_thread_time,
thread_count / (wall_time / 1000.0)
])
func stringify_threaded() -> void:
if data == null:
log_error("No data available for stringify tests")
return
log_subheader("Threaded Stringify Benchmark")
for thread_count in THREAD_COUNTS:
var threads: Array[Thread] = []
var start := Time.get_ticks_usec()
for i in range(thread_count):
var thread := Thread.new()
thread.start(_stringify_thread_func.bind(data))
threads.append(thread)
var total_stringify_time := 0
for thread in threads:
total_stringify_time += thread.wait_to_finish()
var wall_time := Time.get_ticks_usec() - start
var avg_thread_time := float(total_stringify_time / thread_count)
log_info("%d thread(s): wall=%d µs | avg thread=%d µs | throughput=%.1f stringifies/ms" % [
thread_count,
wall_time,
avg_thread_time,
thread_count / (wall_time / 1000.0)
])
static func _parse_thread_func(input: String) -> int:
var start := Time.get_ticks_usec()
YAML.parse(input)
return Time.get_ticks_usec() - start
static func _stringify_thread_func(input_data: Variant) -> int:
var start := Time.get_ticks_usec()
YAML.stringify(input_data)
return Time.get_ticks_usec() - start