I added tries and consult, this is what I get on
8.1.13-27-gd480a2001:
9 ?- go.
Database raw and crude micro benchmark
-> Testing 1,000,000 entries
rec_gen
% 0.468 CPU in 0.469 seconds (100% CPU)
rec_lookup
% 0.426 CPU in 0.427 seconds (100% CPU)
rec_lookup (2nd time)
% 0.422 CPU in 0.423 seconds (100% CPU)
nb_gen
% 0.257 CPU in 0.257 seconds (100% CPU)
nb_lookup
% 0.133 CPU in 0.133 seconds (100% CPU)
nb_lookup (2nd time)
% 0.131 CPU in 0.131 seconds (100% CPU)
asrt_gen
% 0.487 CPU in 0.487 seconds (100% CPU)
asrt_lookup
% 1.366 CPU in 1.369 seconds (100% CPU)
asrt_lookup (2nd time)
% 0.395 CPU in 0.396 seconds (100% CPU)
consult_gen
% 19.954 CPU in 19.979 seconds (100% CPU)
consult_lookup
% 0.300 CPU in 0.301 seconds (100% CPU)
consult_lookup (2nd time)
% 0.300 CPU in 0.301 seconds (100% CPU)
trie_gen
% 0.493 CPU in 0.494 seconds (100% CPU)
trie_lookup
% 0.273 CPU in 0.273 seconds (100% CPU)
trie_lookup (2nd time)
% 0.274 CPU in 0.274 seconds (100% CPU)
Database raw and crude micro benchmark
1,000,000 entries
Database Operation Wall time
-------- --------- ---------
nb 1st lookup .......................... 0.133 secs.
trie 1st lookup .......................... 0.273 secs.
consult 1st lookup .......................... 0.301 secs.
rec 1st lookup .......................... 0.427 secs.
asrt 1st lookup .......................... 1.369 secs.
nb 2nd lookup .......................... 0.131 secs.
trie 2nd lookup .......................... 0.274 secs.
consult 2nd lookup .......................... 0.301 secs.
asrt 2nd lookup .......................... 0.396 secs.
rec 2nd lookup .......................... 0.423 secs.
nb insert .......................... 0.257 secs.
rec insert .......................... 0.469 secs.
asrt insert .......................... 0.487 secs.
trie insert .......................... 0.494 secs.
consult insert .......................... 19.979 secs.
true.
The new code which adds consult and tries, prints the nice table, and stores the results as db_bench
facts (for further processing):
:- dynamic keydb/2,
trie/1,
consult_db/2,
consult_file/1,
db_bench/2.
:- use_module(library(assoc)).
:- use_module(library(apply_macros)).
go :-
writeln('Database raw and crude micro benchmark'),
N = 1 000 000,
format(' -> Testing ~:d entries~n',[N]),
retractall(db_bench(_,_)),
test_db(rec,N),
test_db(nb,N),
test_db(asrt,N),
test_db(consult,N),
test_db(trie,N),
print_header(N),
print_results.
test_db(Name,N) :-
atomic_list_concat([Name,'_',gen],Gen),
atomic_list_concat([Name,'_',lookup],Lookup),
atomic_list_concat([Name,'_',cleanup],Cleanup),
setup_call_cleanup(
( writeln(Gen),
benchmark_goal( [Name,insert], call(Gen,N))
),
( writeln(Lookup),
benchmark_goal( [Name,'1st lookup'], call(Lookup,N)),
write(Lookup), writeln(' (2nd time)'),
benchmark_goal( [Name,'2nd lookup'], call(Lookup,N))
),
( catch( call(Cleanup,N),
error(existence_error(procedure,_),_),
true)
)
) .
/**********************
* Db operations *
**********************/
rec_gen(N) :-
forall( between(1,N,I),
( recordz(I, I)
)
).
rec_lookup(N) :-
forall( between(1,N,I),
( recorded(I, I)
)
).
rec_cleanup(N) :-
forall( between(1,N,I),
( recorded(I, I, Ref), erase(Ref)
)
).
nb_gen(N) :-
forall( between(1,N,I),
%( atom_number(A,I), nb_setval(A, I)
( nb_setval('500', I)
)
).
nb_lookup(N) :-
forall( between(1,N,_),
( nb_getval('500', _)
)
).
nb_cleanup(_) :-
nb_delete('500').
asrt_gen(N) :-
%retractall(keydb(_,_)),
forall( between(1,N,I),
( assertz(keydb(I,I))
)
).
asrt_lookup(N) :-
forall( between(1,N,I),
( keydb(I,I)
)
).
asrt_cleanup(_) :-
retractall(keydb(_,_)).
trie_gen(N) :-
trie_new(Trie),
assertz(trie(Trie)),
forall( between(1,N,I),
( trie_insert(Trie,I,I)
)
).
trie_lookup(N) :-
trie(Trie),
forall( between(1,N,I),
( trie_lookup(Trie,I,I)
)
).
trie_cleanup(_) :-
trie(Trie),
trie_destroy(Trie),
retractall(trie(_)).
consult_gen(N) :-
File = '/tmp/consult_db.db_bench',
assertz(consult_file(File)),
setup_call_cleanup(
open(File,write,Stream),
consult_write_terms(Stream,N),
close(Stream)
),
load_files([File]).
consult_write_terms(Stream,N) :-
forall( between(1,N,I),
( format(Stream,'~w.~n',[consult_db(I,I)])
)
).
consult_lookup(N) :-
forall( between(1,N,I),
( consult_db(I,I)
)
).
consult_cleanup(_) :-
consult_file(F),
retractall(consult_file(_)),
delete_file(F).
/**********************
* Nice printout *
**********************/
print_header(N) :-
nl,
format('~t~w~t~59|~n',['Database raw and crude micro benchmark']),
format('~t~:d entries~t~59|~n',[N]),
format('~w ~t~10|~w ~t~12+~t~48| ~w~n',['Database','Operation','Wall time']),
format('~w ~t~10|~w ~t~12+~t~48| ~w', ['--------','---------','---------']).
print_results :-
bagof( b(Db,W),
S^(db_bench([Db,Type|_], S), get_dict(wall_time,S,W)),
Res),
sort(2,'@<',Res,Sorted),
nl,
maplist( {Type}/[b(Db,Wall)]>>
format('~w ~t~10|~w ~t~12+~`.t~48| ~3f secs.~n',[Db,Type,Wall]),
Sorted),
fail.
print_results.
/****************
* Helpers *
****************/
% Measure, print and store wall and cpu time
% used by Goal.
benchmark_goal(BenchMark,Goal) :-
get_time(OldWall),
statistics(cputime, OldCpu),
call(Goal),
get_time(NewWall),
statistics(cputime, NewCpu),
UsedWall is NewWall - OldWall,
UsedCpu is NewCpu - OldCpu,
assertz( db_bench(BenchMark, stat{ cpu_time: UsedCpu,
wall_time: UsedWall })),
print_message(information, bench(UsedCpu, UsedWall)).
prolog:message(bench(Cpu, Wall)) -->
{ Perc is round(Cpu*100/Wall) },
[ '~3f CPU in ~3f seconds (~w% CPU)' - [Cpu, Wall, Perc] ].