FIFO + paper

This commit is contained in:
Philippe PITTOLI 2024-05-24 00:25:28 +02:00
parent dc34e5b881
commit fefc4e9b26
9 changed files with 146 additions and 58 deletions

View File

@ -5,9 +5,15 @@ Q ?= @
SHOULD_UPDATE = ./bin/should-update SHOULD_UPDATE = ./bin/should-update
DBDIR=/tmp/tests-on-dodb DBDIR=/tmp/tests-on-dodb
RESULTS_DIR=results
benchmark-cars: benchmark-cars:
$(Q)crystal build spec/benchmark-cars.cr $(OPTS) --release $(Q)crystal build spec/benchmark-cars.cr $(OPTS) --release
benchmark-cars-run: benchmark-cars
./benchmark-cars search # by default, test search durations
./bin/stats.sh $(RESULTS_DIR)
./bin/extract-data-benchmark-cars.sh $(RESULTS_DIR)
build: benchmark-cars build: benchmark-cars
wipe-db: wipe-db:

View File

@ -7,8 +7,8 @@ ticks left out from 0 to 350 by 50
label left "Request duration" unaligned "for a partition (ms)" "(Median)" left 0.8 label left "Request duration" unaligned "for a partition (ms)" "(Median)" left 0.8
label bot "Number of cars matching the partition" down 0.1 label bot "Number of cars matching the partition" down 0.1
obram = obuncache = obcache = obsemi = 0 obram = obuncache = obfifo = obcache = obsemi = 0
cbram = cbuncache = cbcache = cbsemi = 0 cbram = cbuncache = cbfifo = cbcache = cbsemi = 0
legendxleft = 1000 legendxleft = 1000
legendxright = 6500 legendxright = 6500
@ -23,21 +23,26 @@ copy "../data/partitions.d" thru X
y_scale = 1000000 y_scale = 1000000
# ram cached semi uncached # ram cached fifo semi uncached
line from cx,$2/y_scale to cx,$4/y_scale line from cx,$2/y_scale to cx,$4/y_scale
line from cx,$5/y_scale to cx,$7/y_scale line from cx,$5/y_scale to cx,$7/y_scale
line from cx,$8/y_scale to cx,$10/y_scale line from cx,$8/y_scale to cx,$10/y_scale
line from cx,$11/y_scale to cx,$13/y_scale line from cx,$11/y_scale to cx,$13/y_scale
line from cx,$14/y_scale to cx,$16/y_scale
#ty = $3 #ty = $3
cbram = $3/y_scale cbram = $3/y_scale
cbcache = $6/y_scale cbcache = $6/y_scale
cbsemi = $9/y_scale cbfifo = $9/y_scale
cbuncache = $12/y_scale cbsemi = $12/y_scale
cbuncache = $15/y_scale
if (obram > 0) then {line from cx,cbram to ox,obram} if (obram > 0) then {line from cx,cbram to ox,obram}
if (obcache > 0) then {line from cx,cbcache to ox,obcache} if (obcache > 0) then {line from cx,cbcache to ox,obcache}
.gcolor pink
if (obfifo > 0) then {line from cx,cbfifo to ox,obfifo}
.gcolor
.gcolor blue .gcolor blue
if (obsemi > 0) then {line from cx,cbsemi to ox,obsemi} if (obsemi > 0) then {line from cx,cbsemi to ox,obsemi}
.gcolor .gcolor
@ -47,15 +52,19 @@ copy "../data/partitions.d" thru X
obram = cbram obram = cbram
obcache = cbcache obcache = cbcache
obfifo = cbfifo
obsemi = cbsemi obsemi = cbsemi
obuncache = cbuncache obuncache = cbuncache
ox = cx ox = cx
# ram cached semi uncached # ram cached fifo semi uncached
.gcolor red .gcolor red
bullet at cx,cbram bullet at cx,cbram
.gcolor .gcolor
bullet at cx,cbcache bullet at cx,cbcache
.gcolor pink
bullet at cx,cbfifo
.gcolor
.gcolor blue .gcolor blue
bullet at cx,cbsemi bullet at cx,cbsemi
.gcolor .gcolor

View File

@ -6,8 +6,8 @@ ticks left out from 0 to 170 by 20
label left "Request duration" unaligned "for a tag (ms)" "(Median)" left 0.8 label left "Request duration" unaligned "for a tag (ms)" "(Median)" left 0.8
label bot "Number of cars matching the tag" down 0.1 label bot "Number of cars matching the tag" down 0.1
obram = obuncache = obcache = obsemi = 0 obram = obuncache = obfifo = obcache = obsemi = 0
cbram = cbuncache = cbcache = cbsemi = 0 cbram = cbuncache = cbfifo = cbcache = cbsemi = 0
legendxleft = 200 legendxleft = 200
legendxright = 3000 legendxright = 3000
@ -22,21 +22,26 @@ copy "../data/tags.d" thru X
y_scale = 1000000 y_scale = 1000000
# ram cached semi uncached # ram cached fifo semi uncached
line from cx,$2/y_scale to cx,$4/y_scale line from cx,$2/y_scale to cx,$4/y_scale
line from cx,$5/y_scale to cx,$7/y_scale line from cx,$5/y_scale to cx,$7/y_scale
line from cx,$8/y_scale to cx,$10/y_scale line from cx,$8/y_scale to cx,$10/y_scale
line from cx,$11/y_scale to cx,$13/y_scale line from cx,$11/y_scale to cx,$13/y_scale
line from cx,$14/y_scale to cx,$16/y_scale
#ty = $3 #ty = $3
cbram = $3/y_scale cbram = $3/y_scale
cbcache = $6/y_scale cbcache = $6/y_scale
cbsemi = $9/y_scale cbfifo = $9/y_scale
cbuncache = $12/y_scale cbsemi = $12/y_scale
cbuncache = $15/y_scale
if (obram > 0) then {line from cx,cbram to ox,obram} if (obram > 0) then {line from cx,cbram to ox,obram}
if (obcache > 0) then {line from cx,cbcache to ox,obcache} if (obcache > 0) then {line from cx,cbcache to ox,obcache}
.gcolor pink
if (obfifo > 0) then {line from cx,cbfifo to ox,obfifo}
.gcolor
.gcolor blue .gcolor blue
if (obsemi > 0) then {line from cx,cbsemi to ox,obsemi} if (obsemi > 0) then {line from cx,cbsemi to ox,obsemi}
.gcolor .gcolor
@ -46,15 +51,19 @@ copy "../data/tags.d" thru X
obram = cbram obram = cbram
obcache = cbcache obcache = cbcache
obfifo = cbfifo
obsemi = cbsemi obsemi = cbsemi
obuncache = cbuncache obuncache = cbuncache
ox = cx ox = cx
# ram cached semi uncached # ram cached fifo semi uncached
.gcolor red .gcolor red
bullet at cx,cbram bullet at cx,cbram
.gcolor .gcolor
bullet at cx,cbcache bullet at cx,cbcache
.gcolor pink
bullet at cx,cbfifo
.gcolor
.gcolor blue .gcolor blue
bullet at cx,cbsemi bullet at cx,cbsemi
.gcolor .gcolor

View File

@ -19,7 +19,7 @@ define legend {
diffx = xright - xleft diffx = xright - xleft
diffy = yup - ydown diffy = yup - ydown
hdiff = diffy/4.3 hdiff = diffy/5.7
cy = yup - (diffy/6) cy = yup - (diffy/6)
cx = (diffx/20) + xleft cx = (diffx/20) + xleft
@ -27,6 +27,7 @@ define legend {
lendx = cx + diffx/8 lendx = cx + diffx/8
tstartx = lendx + diffx/20 tstartx = lendx + diffx/20
.ps -2
.gcolor red .gcolor red
line from lstartx,cy to lendx,cy line from lstartx,cy to lendx,cy
.gcolor .gcolor
@ -35,6 +36,11 @@ define legend {
line from lstartx,cy to lendx,cy line from lstartx,cy to lendx,cy
"Cached db and index" ljust at tstartx,cy "Cached db and index" ljust at tstartx,cy
cy = cy - hdiff cy = cy - hdiff
.gcolor pink
line from lstartx,cy to lendx,cy
.gcolor
"FIFO db and cached index" ljust at tstartx,cy
cy = cy - hdiff
.gcolor blue .gcolor blue
line from lstartx,cy to lendx,cy line from lstartx,cy to lendx,cy
.gcolor .gcolor
@ -44,4 +50,5 @@ define legend {
line from lstartx,cy to lendx,cy line from lstartx,cy to lendx,cy
.gcolor .gcolor
"Uncached db and index" ljust at tstartx,cy "Uncached db and index" ljust at tstartx,cy
.ps +2
} }

View File

@ -13,13 +13,6 @@ require "./db-cars.cr"
# ENV["NBRUN"] rescue 100 # ENV["NBRUN"] rescue 100
# ENV["MAXINDEXES"] rescue 5_000 # ENV["MAXINDEXES"] rescue 5_000
class DODB::Storage(V)
def empty_db
while pop
end
end
end
class Context class Context
class_property report_dir = "results" class_property report_dir = "results"
class_property max_indexes = 5_000 class_property max_indexes = 5_000
@ -85,26 +78,12 @@ def prepare_env(storage, name, s_index, s_partition, s_tags, &)
long_operation "removing #{name} data" { storage.rm_storage_dir } long_operation "removing #{name} data" { storage.rm_storage_dir }
end end
def batch() def search_benchmark(storage : DODB::Storage(Car),
cars_ram = SPECDB::RAMOnly(Car).new
cars_cached = SPECDB::Cached(Car).new
cars_fifo = DODB::FIFOSpecDataBase(Car).new
cars_semi = SPECDB::Uncached(Car).new "-semi"
cars_uncached = SPECDB::Uncached(Car).new
ram_Sby_name, ram_Sby_color, ram_Sby_keywords = ram_indexes cars_ram
cached_Sby_name, cached_Sby_color, cached_Sby_keywords = cached_indexes cars_cached
fifo_Sby_name, fifo_Sby_color, fifo_Sby_keywords = cached_indexes cars_fifo
semi_Sby_name, semi_Sby_color, semi_Sby_keywords = cached_indexes cars_semi
uncached_Sby_name, uncached_Sby_color, uncached_Sby_keywords = uncached_indexes cars_uncached
fn = ->(storage : DODB::Storage(Car),
current_db_size : Int32, current_db_size : Int32,
name : String, name : String,
search_name : DODB::Index::Basic(Car), search_name : DODB::Index::Basic(Car),
search_color : DODB::Index::Partition(Car), search_color : DODB::Index::Partition(Car),
search_keywords : DODB::Index::Tags(Car)) { search_keywords : DODB::Index::Tags(Car))
name_to_search = ENV["CARNAME"] rescue "Corvet-#{(current_db_size/2).to_i}" name_to_search = ENV["CARNAME"] rescue "Corvet-#{(current_db_size/2).to_i}"
color_to_search = ENV["CARCOLOR"] rescue "red" color_to_search = ENV["CARCOLOR"] rescue "red"
keyword_to_search = ENV["CARKEYWORD"] rescue "spacious" keyword_to_search = ENV["CARKEYWORD"] rescue "spacious"
@ -123,7 +102,22 @@ def batch()
fake_report("#{name}_#{current_db_size}_partitions") fake_report("#{name}_#{current_db_size}_partitions")
fake_report("#{name}_#{current_db_size}_tags") fake_report("#{name}_#{current_db_size}_tags")
end end
} end
def bench_searches()
cars_ram = SPECDB::RAMOnly(Car).new
cars_cached = SPECDB::Cached(Car).new
cars_fifo = SPECDB::FIFO(Car).new "", 5000 # With only 5_000 entries
cars_semi = SPECDB::Uncached(Car).new "-semi"
cars_uncached = SPECDB::Uncached(Car).new
ram_Sby_name, ram_Sby_color, ram_Sby_keywords = ram_indexes cars_ram
cached_Sby_name, cached_Sby_color, cached_Sby_keywords = cached_indexes cars_cached
fifo_Sby_name, fifo_Sby_color, fifo_Sby_keywords = cached_indexes cars_fifo
semi_Sby_name, semi_Sby_color, semi_Sby_keywords = cached_indexes cars_semi
uncached_Sby_name, uncached_Sby_color, uncached_Sby_keywords = uncached_indexes cars_uncached
fn = ->search_benchmark(DODB::Storage(Car), Int32, String, DODB::Index::Basic(Car), DODB::Index::Partition(Car), DODB::Index::Tags(Car))
prepare_env cars_ram, "ram", ram_Sby_name, ram_Sby_color, ram_Sby_keywords, &fn prepare_env cars_ram, "ram", ram_Sby_name, ram_Sby_color, ram_Sby_keywords, &fn
prepare_env cars_cached, "cached", cached_Sby_name, cached_Sby_color, cached_Sby_keywords, &fn prepare_env cars_cached, "cached", cached_Sby_name, cached_Sby_color, cached_Sby_keywords, &fn
@ -143,14 +137,16 @@ def perform_add(storage : DODB::Storage(Car))
end end
end end
def batch_add() def bench_add()
cars_ram = SPECDB::RAMOnly(Car).new cars_ram = SPECDB::RAMOnly(Car).new
cars_cached = SPECDB::Cached(Car).new cars_cached = SPECDB::Cached(Car).new
cars_fifo = SPECDB::FIFO(Car).new "", 5_000
cars_semi = SPECDB::Uncached(Car).new "-semi" cars_semi = SPECDB::Uncached(Car).new "-semi"
cars_uncached = SPECDB::Uncached(Car).new cars_uncached = SPECDB::Uncached(Car).new
ram_indexes cars_ram ram_indexes cars_ram
cached_indexes cars_cached cached_indexes cars_cached
cached_indexes cars_fifo
cached_indexes cars_semi cached_indexes cars_semi
uncached_indexes cars_uncached uncached_indexes cars_uncached
@ -160,6 +156,9 @@ def batch_add()
avr = perform_add(cars_cached) avr = perform_add(cars_cached)
puts "(cached db and indexes) add a value (average on #{Context.nb_run} tries): #{avr}" puts "(cached db and indexes) add a value (average on #{Context.nb_run} tries): #{avr}"
avr = perform_add(cars_fifo)
puts "(fifo db and cached indexes) add a value (average on #{Context.nb_run} tries): #{avr}"
avr = perform_add(cars_semi) avr = perform_add(cars_semi)
puts "(uncached db but cached indexes) add a value (average on #{Context.nb_run} tries): #{avr}" puts "(uncached db but cached indexes) add a value (average on #{Context.nb_run} tries): #{avr}"
@ -172,6 +171,22 @@ def batch_add()
cars_uncached.rm_storage_dir cars_uncached.rm_storage_dir
end end
def bench_50_shades_of_fifo()
cars_fifo1 = SPECDB::FIFO(Car).new "", 1_000
cars_fifo5 = SPECDB::FIFO(Car).new "", 5_000
cars_fifo10 = SPECDB::FIFO(Car).new "", 10_000
fifo_Sby_name1, fifo_Sby_color1, fifo_Sby_keywords1 = cached_indexes cars_fifo1
fifo_Sby_name5, fifo_Sby_color5, fifo_Sby_keywords5 = cached_indexes cars_fifo5
fifo_Sby_name10, fifo_Sby_color10, fifo_Sby_keywords10 = cached_indexes cars_fifo10
fn = ->search_benchmark(DODB::Storage(Car), Int32, String, DODB::Index::Basic(Car), DODB::Index::Partition(Car), DODB::Index::Tags(Car))
prepare_env cars_fifo1, "fifo1", fifo_Sby_name1, fifo_Sby_color1, fifo_Sby_keywords1, &fn
prepare_env cars_fifo5, "fifo5", fifo_Sby_name5, fifo_Sby_color5, fifo_Sby_keywords5, &fn
prepare_env cars_fifo10, "fifo10", fifo_Sby_name10, fifo_Sby_color10, fifo_Sby_keywords10, &fn
end
ENV["REPORT_DIR"]?.try { |report_dir| Context.report_dir = report_dir } ENV["REPORT_DIR"]?.try { |report_dir| Context.report_dir = report_dir }
Dir.mkdir_p Context.report_dir Dir.mkdir_p Context.report_dir
@ -187,5 +202,18 @@ pp! Context.to
pp! Context.incr pp! Context.incr
pp! Context.max_indexes pp! Context.max_indexes
batch if ARGV.size == 0
batch_add puts "Usage: benchmark-cars (fifo|search|add)"
exit 0
end
case ARGV[0]
when /fifo/
bench_50_shades_of_fifo
when /search/
bench_searches
when /add/
bench_add
else
puts "Usage: benchmark-cars (fifo|search|add)"
end

View File

@ -24,10 +24,10 @@ class SPECDB::Cached(V) < DODB::Storage::Cached(V)
end end
end end
class DODB::FIFOSpecDataBase(V) < DODB::Storage::Stacked(V) class SPECDB::FIFO(V) < DODB::Storage::Stacked(V)
property storage_dir : String property storage_dir : String
def initialize(storage_ext = "", remove_previous_data = true) def initialize(storage_ext = "", @max_entries = 100_000, remove_previous_data = true)
@storage_dir = "specdb-storage-fifo#{storage_ext}" @storage_dir = "specdb-storage-fifo-#{@max_entries}#{storage_ext}"
::FileUtils.rm_rf storage_dir if remove_previous_data ::FileUtils.rm_rf storage_dir if remove_previous_data
super storage_dir super storage_dir
end end

View File

@ -73,7 +73,6 @@ class DODB::Storage::Cached(V) < DODB::Storage(V)
@data[key] rescue raise MissingEntry.new(key) @data[key] rescue raise MissingEntry.new(key)
end end
# :inherit:
def []=(key : Int32, value : V) def []=(key : Int32, value : V)
old_value = self.[key]? old_value = self.[key]?

View File

@ -31,7 +31,6 @@
# ``` # ```
# #
# NOTE: fast for frequently requested data and requires a stable (and configurable) amount of memory. # NOTE: fast for frequently requested data and requires a stable (and configurable) amount of memory.
# TODO: not yet implemented.
class DODB::Storage::Stacked(V) < DODB::Storage::Cached(V) class DODB::Storage::Stacked(V) < DODB::Storage::Cached(V)
# The *stack* a simple FIFO instance where the key of the requested data is pushed. # The *stack* a simple FIFO instance where the key of the requested data is pushed.
# In case the number of stored entries exceeds what is allowed, the least recently used entry is removed. # In case the number of stored entries exceeds what is allowed, the least recently used entry is removed.
@ -52,9 +51,35 @@ class DODB::Storage::Stacked(V) < DODB::Storage::Cached(V)
def [](key : Int32) : V def [](key : Int32) : V
val = @data[key] rescue raise MissingEntry.new(key) val = @data[key] rescue raise MissingEntry.new(key)
push_fifo key
val
end
# Assumes new entries are more requested than old ones.
def []=(key : Int32, value : V)
super key, value
push_fifo key
end
# :inherit:
#
# Assumes new entries are more requested than old ones.
def <<(item : V)
key = super item
push_fifo key
end
def unsafe_delete(key : Int32)
@stack.delete key if super key
end
def delete(key : Int32)
@stack.delete key if super key
end
private def push_fifo(key : Int32)
if entry_to_remove = @stack << key if entry_to_remove = @stack << key
@data.delete entry_to_remove @data.delete entry_to_remove
end end
val
end end
end end

View File

@ -27,11 +27,16 @@ class FIFO(V)
end end
# Pushes a value in the FIFO and gets the oldest value whether it exceeds the allowed number of entries. # Pushes a value in the FIFO and gets the oldest value whether it exceeds the allowed number of entries.
# NOTE: `#<<(v : V)` is the only function since it's enough for the intended use, feel free to improve this. # NOTE: `#<<(v : V)` is (almost) the only function since it's enough for the intended use, feel free to improve this.
# WARNING: implementation is extremely simple (3 lines) and not designed to be highly efficient. # WARNING: implementation is extremely simple (3 lines) and not designed to be highly efficient.
def <<(v : V) : V? def <<(v : V) : V?
@data.select! { |x| v != v } # remove dups @data.select! { |x| v != v } # remove dups
@data.unshift v # push on top of the stack @data.unshift v # push on top of the stack
@data.pop if @data.size > @max_entries # remove least recently used entry if `@data` is too big @data.pop if @data.size > @max_entries # remove least recently used entry if `@data` is too big
end end
# Removes a value.
def delete(v : V)
@data.select! { |x| v != v }
end
end end