From 7cc26adf58f9a78291f9fda0b6325974d6b73313 Mon Sep 17 00:00:00 2001 From: Lily Rose Date: Thu, 24 Jul 2025 17:45:23 +1000 Subject: [PATCH] Move benchmarks to tests --- gleam.toml | 2 +- manifest.toml | 4 +- src/kicad_sexpr.gleam | 92 ------------------------ test/kicad_sexpr_test.gleam | 136 ++++++++++++++++++++++++++++++++++-- 4 files changed, 133 insertions(+), 101 deletions(-) diff --git a/gleam.toml b/gleam.toml index 60af32b..fdbd197 100644 --- a/gleam.toml +++ b/gleam.toml @@ -15,7 +15,7 @@ version = "1.0.0" [dependencies] gleam_stdlib = ">= 0.44.0 and < 2.0.0" simplifile = ">= 2.3.0 and < 3.0.0" -splitter = ">= 1.0.0 and < 2.0.0" [dev-dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" +gleam_time = ">= 1.4.0 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml index a14c26a..beaf72a 100644 --- a/manifest.toml +++ b/manifest.toml @@ -4,13 +4,13 @@ packages = [ { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" }, { name = "gleam_stdlib", version = "0.62.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "DC8872BC0B8550F6E22F0F698CFE7F1E4BDA7312FDEB40D6C3F44C5B706C8310" }, + { name = "gleam_time", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "DCDDC040CE97DA3D2A925CDBBA08D8A78681139745754A83998641C8A3F6587E" }, { name = "gleeunit", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "63022D81C12C17B7F1A60E029964E830A4CBD846BBC6740004FC1F1031AE0326" }, { name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" }, - { name = "splitter", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "splitter", source = "hex", outer_checksum = "128FC521EE33B0012E3E64D5B55168586BC1B9C8D7B0D0CA223B68B0D770A547" }, ] [requirements] gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } +gleam_time = { version = ">= 1.4.0 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } simplifile = { version = ">= 2.3.0 and < 3.0.0" } -splitter = { version = ">= 1.0.0 and < 2.0.0" } diff --git a/src/kicad_sexpr.gleam b/src/kicad_sexpr.gleam index be94e27..8b13789 100644 --- a/src/kicad_sexpr.gleam +++ b/src/kicad_sexpr.gleam @@ -1,93 +1 @@ -import gleam/float -import gleam/int -import gleam/io -import gleam/list -import gleam/result -import gleam/string -import kicad_sexpr/decode -import kicad_sexpr/parse -import kicad_sexpr/token -import simplifile -fn print_stats(title: String, successes: Int, total: Int) { - io.println( - title - <> ": " - <> int.to_string(successes) - <> "/" - <> int.to_string(total) - <> " (" - <> int.to_float(100 * successes) /. int.to_float(total) - |> float.to_precision(2) - |> float.to_string - |> string.append("%") - <> ")", - ) -} - -pub fn main() -> Nil { - let assert Ok(file_names) = - simplifile.get_files("/usr/share/kicad/footprints") - - // let #(file_names, _) = file_names |> list.drop(0) |> list.split(1000) - // let file_names = list.sample(file_names, 1000) - // let file_names = ["/usr/share/kicad/symbols/RF_Module.kicad_sym"] - - let num_file_names = list.length(file_names) - io.println("Total: " <> int.to_string(num_file_names)) - - let #(successfully_read, _failed_to_read) = - file_names - |> list.map(fn(file_name) { - simplifile.read_bits(file_name) - |> result.map(fn(res) { #(file_name, res) }) - |> result.map_error(fn(res) { #(file_name, res) }) - }) - |> result.partition - let num_successfully_read = list.length(successfully_read) - print_stats("Read", num_successfully_read, num_file_names) - - let #(successfully_parsed, _failed_to_parse) = - successfully_read - |> list.map(fn(data) { - let #(file_name, file_contents) = data - parse.run(file_contents) - |> result.map(fn(res) { #(file_name, file_contents, res) }) - |> result.map_error(fn(res) { #(file_name, file_contents, res) }) - }) - |> result.partition - let num_successfully_parsed = list.length(successfully_parsed) - print_stats("Parsed", num_successfully_parsed, num_successfully_read) - - let #(successfully_decoded, failed_to_decode) = - successfully_parsed - |> list.map(fn(data) { - let #(file_name, file_contents, sexpr) = data - decode.run(token.footprint_file, sexpr) - |> result.map(fn(res) { #(file_name, file_contents, sexpr, res) }) - |> result.map_error(fn(res) { #(file_name, file_contents, sexpr, res) }) - }) - |> result.partition - let num_successfully_decoded = list.length(successfully_decoded) - print_stats("Decoded", num_successfully_decoded, num_successfully_parsed) - list.each(failed_to_decode, fn(data) { - let #(file_name, _file_contents, _sexpr, error) = data - io.println(file_name) - echo error - // panic - }) - - // let assert Ok(footprint_str) = - // simplifile.read( - // "/usr/share/kicad/footprints/Relay_SMD.pretty/Relay_DPDT_AXICOM_IMSeries_JLeg.kicad_mod", - // ) - // // let assert Ok(footprint_str) = simplifile.read("test2.kicad_mod") - // let assert Ok(t) = - // parse.run( - // " (wobble \"hi there \\\" \\\\ this is a test\" (wibble foo bar) bar) ", - // ) - // io.println(parse.sexpr_to_pretty_string(t)) - // let assert Ok(t) = decode.run(wobble, t) - // echo t - Nil -} diff --git a/test/kicad_sexpr_test.gleam b/test/kicad_sexpr_test.gleam index fba3c88..987542d 100644 --- a/test/kicad_sexpr_test.gleam +++ b/test/kicad_sexpr_test.gleam @@ -1,13 +1,137 @@ +import gleam/float +import gleam/int +import gleam/io +import gleam/list +import gleam/result +import gleam/string +import gleam/time/duration +import gleam/time/timestamp.{type Timestamp} import gleeunit +import kicad_sexpr/decode.{type Decoder, type NextFn} +import kicad_sexpr/parse +import kicad_sexpr/token +import simplifile pub fn main() -> Nil { + io.println("\nTesting Footprints") + test_read_parse_decode("/usr/share/kicad/footprints", token.footprint_file) + io.println("\nTesting Symbol Libraries") + test_read_parse_decode("/usr/share/kicad/symbols", token.symbol_library) gleeunit.main() } -// gleeunit test functions end in `_test` -pub fn hello_world_test() { - let name = "Joe" - let greeting = "Hello, " <> name <> "!" - - assert greeting == "Hello, Joe!" +fn time_taken_string(start_time: Timestamp, end_time: Timestamp) -> String { + let #(s, us) = + timestamp.difference(start_time, end_time) + |> duration.to_seconds_and_nanoseconds + int.to_string(int.absolute_value(s)) + <> "." + <> int.to_string(us / 1_000_000) + <> "s" +} + +fn print_stats( + title: String, + successes: Int, + total: Int, + start_time: Timestamp, + end_time: Timestamp, +) -> Nil { + io.println( + title + <> int.to_string(successes) + <> "/" + <> int.to_string(total) + <> " (" + <> int.to_float(100 * successes) /. int.to_float(total) + |> float.to_precision(1) + |> float.to_string + |> string.pad_start(5, "0") + |> string.append("%") + <> ") in " + <> time_taken_string(start_time, end_time), + ) +} + +fn test_read_parse_decode( + path: String, + decoder: fn(NextFn(a, a)) -> Decoder(a), +) -> Nil { + let assert Ok(file_names) = simplifile.get_files(path) + + // let #(file_names, _) = file_names |> list.drop(0) |> list.split(1000) + // let file_names = list.sample(file_names, 1000) + // let file_names = ["/usr/share/kicad/symbols/RF_Module.kicad_sym"] + + let num_file_names = list.length(file_names) + io.println("Total: " <> int.to_string(num_file_names)) + + let time_before_read = timestamp.system_time() + let #(successfully_read, _failed_to_read) = + file_names + |> list.map(fn(file_name) { + simplifile.read_bits(file_name) + |> result.map(fn(res) { #(file_name, res) }) + |> result.map_error(fn(res) { #(file_name, res) }) + }) + |> result.partition + let time_after_read = timestamp.system_time() + let num_successfully_read = list.length(successfully_read) + print_stats( + "Read: ", + num_successfully_read, + num_file_names, + time_before_read, + time_after_read, + ) + + let time_before_parse = timestamp.system_time() + let #(successfully_parsed, _failed_to_parse) = + successfully_read + |> list.map(fn(data) { + let #(file_name, file_contents) = data + parse.run(file_contents) + |> result.map(fn(res) { #(file_name, file_contents, res) }) + |> result.map_error(fn(res) { #(file_name, file_contents, res) }) + }) + |> result.partition + let time_after_parse = timestamp.system_time() + let num_successfully_parsed = list.length(successfully_parsed) + print_stats( + "Parsed: ", + num_successfully_parsed, + num_successfully_read, + time_before_parse, + time_after_parse, + ) + + let time_before_decode = timestamp.system_time() + let #(successfully_decoded, failed_to_decode) = + successfully_parsed + |> list.map(fn(data) { + let #(file_name, file_contents, sexpr) = data + decode.run(decoder, sexpr) + |> result.map(fn(res) { #(file_name, file_contents, sexpr, res) }) + |> result.map_error(fn(res) { #(file_name, file_contents, sexpr, res) }) + }) + |> result.partition + let time_after_decode = timestamp.system_time() + let num_successfully_decoded = list.length(successfully_decoded) + print_stats( + "Decoded: ", + num_successfully_decoded, + num_successfully_parsed, + time_before_decode, + time_after_decode, + ) + list.each(failed_to_decode, fn(data) { + let #(file_name, _file_contents, _sexpr, error) = data + io.println(file_name) + echo error + // panic + }) + io.println( + "Total Time Taken: " + <> time_taken_string(time_before_read, time_after_decode), + ) }