From d91452a5aee0322e8345c7b70786338c1e1e55b9 Mon Sep 17 00:00:00 2001 From: Philippe PITTOLI Date: Sat, 4 May 2024 23:12:32 +0200 Subject: [PATCH] Add a very clumsy benchmark on a car database. --- spec/benchmark-cars.cr | 141 ++++++++++++++++++++++++++++++++++++ spec/benchmark-utilities.cr | 32 ++++++++ spec/test-data.cr | 19 +++++ 3 files changed, 192 insertions(+) create mode 100644 spec/benchmark-cars.cr create mode 100644 spec/benchmark-utilities.cr diff --git a/spec/benchmark-cars.cr b/spec/benchmark-cars.cr new file mode 100644 index 0000000..bb0eda3 --- /dev/null +++ b/spec/benchmark-cars.cr @@ -0,0 +1,141 @@ +require "benchmark" +require "./benchmark-utilities.cr" + +require "../src/dodb.cr" +require "./test-data.cr" + +class DODBCachedCars < DODB::CachedDataBase(Car) + property storage_dir : String + def initialize(storage_ext = "", remove_previous_data = true) + @storage_dir = "test-storage-cars-cached#{storage_ext}" + + if remove_previous_data + ::FileUtils.rm_rf storage_dir + end + + super storage_dir + end + + def rm_storage_dir + ::FileUtils.rm_rf @storage_dir + end +end + +class DODBUnCachedCars < DODB::DataBase(Car) + property storage_dir : String + def initialize(storage_ext = "", remove_previous_data = true) + @storage_dir = "test-storage-cars-uncached#{storage_ext}" + + if remove_previous_data + ::FileUtils.rm_rf storage_dir + end + + super storage_dir + end + + def rm_storage_dir + ::FileUtils.rm_rf @storage_dir + end +end + +def init_indexes(storage : DODB::Storage) + n = storage.new_index "name", &.name + c = storage.new_partition "color", &.color + k = storage.new_tags "keyword", &.keywords + return n, c, k +end + +def add_cars(storage : DODB::Storage, nb_iterations : Int32) + i = 0 + car1 = Car.new "Corvet", "red", [ "shiny", "impressive", "fast", "elegant" ] + car2 = Car.new "Bullet-GT", "blue", [ "shiny", "fast", "expensive" ] + car3 = Car.new "Deudeuche", "beige", [ "curvy", "sublime" ] + car4 = Car.new "Ford-5", "red", [ "unknown" ] + car5 = Car.new "C-MAX", "gray", [ "spacious", "affordable" ] + + while i < nb_iterations + car1.name = "Corvet-#{i}" + car2.name = "Bullet-GT-#{i}" + car3.name = "Deudeuche-#{i}" + car4.name = "Ford-5-#{i}" + car5.name = "C-MAX-#{i}" + + storage << car1 + storage << car2 + storage << car3 + storage << car4 + storage << car5 + i += 1 + STDOUT.write "\radding value #{i}".to_slice + end + puts "" +end + +cars_cached = DODBCachedCars.new +cars_uncached = DODBUnCachedCars.new + +cached_searchby_name, cached_searchby_color, cached_searchby_keywords = init_indexes cars_cached +uncached_searchby_name, uncached_searchby_color, uncached_searchby_keywords = init_indexes cars_uncached + +add_cars cars_cached, 1_000 +add_cars cars_uncached, 1_000 + +# Searching for data with an index. +Benchmark.ips do |x| + x.report("(cars db) searching a data with an index (with a cache)") do + corvet = cached_searchby_name.get "Corvet-500" + end + + x.report("(cars db) searching a data with an index (without a cache)") do + corvet = uncached_searchby_name.get "Corvet-500" + end +end + +# Searching for data with a partition. +Benchmark.ips do |x| + x.report("(cars db) searching a data with a partition (with a cache)") do + red_cars = cached_searchby_color.get "red" + end + + x.report("(cars db) searching a data with a partition (without a cache)") do + red_cars = cached_searchby_color.get "red" + end +end + +# Searching for data with a tag. +Benchmark.ips do |x| + x.report("(cars db) searching a data with a tag (with a cache)") do + red_cars = cached_searchby_keywords.get "spacious" + end + + x.report("(cars db) searching a data with a tag (without a cache)") do + red_cars = cached_searchby_keywords.get "spacious" + end +end + +cars_cached.rm_storage_dir +cars_uncached.rm_storage_dir + +cars_cached = DODBCachedCars.new +cars_uncached = DODBUnCachedCars.new + +#init_indexes cars_cached +#init_indexes cars_uncached +cached_searchby_name, cached_searchby_color, cached_searchby_keywords = init_indexes cars_cached +uncached_searchby_name, uncached_searchby_color, uncached_searchby_keywords = init_indexes cars_uncached + +add_cars cars_cached, 1_000 +add_cars cars_uncached, 1_000 + +nb_run = 1000 + +perform_benchmark_average_verbose "(cached) search db with an index", nb_run, do + cached_searchby_name.get "Corvet-500" +end + +perform_benchmark_average_verbose "(uncached) search db with an index", nb_run, do + uncached_searchby_name.get "Corvet-500" +end + +cars_cached.rm_storage_dir +cars_uncached.rm_storage_dir diff --git a/spec/benchmark-utilities.cr b/spec/benchmark-utilities.cr new file mode 100644 index 0000000..5627560 --- /dev/null +++ b/spec/benchmark-utilities.cr @@ -0,0 +1,32 @@ +def perform_something(&block) + start = Time.monotonic + yield + Time.monotonic - start +end + +def perform_benchmark_average(ntimes : Int32, &block) + i = 1 + sum = Time::Span.zero + while i <= ntimes + elapsed_time = perform_something &block + sum += elapsed_time + i += 1 + end + + sum / ntimes +end + +def perform_benchmark_average_verbose(title : String, ntimes : Int32, &block) + i = 1 + sum = Time::Span.zero + puts "Execute '#{title}' × #{ntimes}" + while i <= ntimes + elapsed_time = perform_something &block + sum += elapsed_time + STDOUT.write "\relapsed_time: #{elapsed_time}, average: #{sum/i}".to_slice + + i += 1 + end + puts "" + puts "Average: #{sum/ntimes}" +end diff --git a/spec/test-data.cr b/spec/test-data.cr index 2df42ed..09be46d 100644 --- a/spec/test-data.cr +++ b/spec/test-data.cr @@ -85,3 +85,22 @@ class PrimitiveShip @@asakaze ] end + +class Car + include JSON::Serializable + + property name : String # unique to each instance (1-1 relations) + property color : String # a simple attribute (1-n relations) + property keywords : Array(String) # tags about a car, example: "shiny" (n-n relations) + + def initialize(@name, @color, @keywords) + end + class_getter cars = [ + Car.new("Corvet", "red", [ "shiny", "impressive", "fast", "elegant" ]), + Car.new("SUV", "red", [ "solid", "impressive" ]), + Car.new("Mustang", "red", [ "shiny", "impressive", "elegant" ]), + Car.new("Bullet-GT", "red", [ "shiny", "impressive", "fast", "elegant" ]), + Car.new("GTI", "blue", [ "average" ]), + Car.new("Deudeuch", "violet", [ "dirty", "slow", "only French will understand" ]) + ] +end