Database micro-benchmark (Discussion)

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] ].

1 Like