%%%    大容量ヒープ領域のテストプログラム
%%%
%%% 概要：このプログラムは、指定値または、ヒープ領域の限界まで、複雑な単位節をアサートし、
%%%       その最後尾の単位節から値を取得する時間を調べるものです。
%%%
%%%    起動　>prolog -h ヒープ領域サイズ(Kセル) -s heap_test.pl
%%%
%%% １）PCに実装された利用可能メモリ量を調べます。
%%%     windowsでは、タスクマネージャを開き、パフォーマンスタグの「空きメモリ」です。
%%%
%%% ２）Prologインタプリタ起動時オプションでヒープ領域を（１）以内の適量設定します。
%%%     単位はKセルなので、 指定値の1024倍が設定されます。
%%% 
%%%     ヒープ、アトムとも、1セルのサイズは６４ビット版では16バイト、３２ビット版では８バイトですので、
%%%     １指定するごとに６４ビット版では１６３８４バイト（１６Kバイト）のメモリを消費することになります。
%%%
%%%     ６４ビット版でヒープに1ギガバイト(2^30)のメモリを割り当てるには、
%%%     | ?- X is 2^30/(1024*16).   X= 65536 ですので、　>prolog -h 65536 となります。
%%%
%%% ３） 本テストでは、一節につきヒープ領域５０セル消費します
%%%     ６４ビット版では、可能ならば４Gを超えるヒープ領域( -h 264000 ）をとってテストてみて
%%%     ください。（４Gヒープは生成にたいへん時間がかかりますが５４０万単位節に相当します）
%%% 
%%% ４）インタプリタを立ち上げての領域サイズは、組込み述語　statistics/0 is/2で調べられます。
%%%     | ?- statistics.
%%%     | ?- FreeHeapCell is heapmax-heapused, HeapMegabyte is heapmax*16/2^20.
%%% 
%%% ５）テストの起動
%%%     | ?- test.          領域限界までの個数の単位節を生成し最終節の検索テストをします。
%%%     | ?- test(100000).  引数で指定した個数の単位節を生成し最終節の検索テストをします。
%%%     | ?- next_test.     生成分での検索テストをおこないます（中断したあとでの利用など）

:- s_mode(_,on).

test:- test(_).
test(VOLUME):- 
        s_new,s_reclaim,
        statistics,
        Hp is (heapmax-heapused-100)/50,   % At is atommax-atomused-20,
         min(At,Hp,Vol0),                  % アトム限界とヒープ限界の小さいほう
         min(VOLUME,Vol0,Vol),
        write_line,
        write(Vol),write('の単位節を生成します'),nl,
        write('途中で中断するには、コントロールキーとCを同時に押し Abortまたはbreak を指定して'),nl,
        write('| ?-next_test. で生成済分での検索テストがおこなえます'),nl,nl,
        T0 is cputime,Vole is Vol-1,
           repeat(N),mk_unit(N,X),asserta(X),
             (0 is N mod 10000 -> TX is cputime,write(N),tab(1);true),
           N==Vole,!,
        T0t is cputime-T0,nl,
        write_line,
        clause(data,5,Vols),
        write([Vols,' Clause Done! ',T0t,' seconds']),nl,nl,
        next_test.

min(A,B,A):-integer(A), A<B,!.
min(_,A,A).

next_test:-
        write_line,
        clause(data,5,Vol),write(単位節の個数=Vol),statistics,
        write_line,
        write(最終定義単位節を第一引数で検索します),nl,
        Data1 = data(0,_a,_b,_c,_d),
        writeq(call= Data1),nl,
        T1 is cputime,
                  Data1,!,
        T1t is cputime-T1,
        writeq(succ= Data1),nl,
        write(T1t='seconds '),nl,
        write_line,
        write(最終定義単位節を第5引数のリストの最終要素で検索します),nl,
        Data2 = data(_0,_1,_2,_3,[_4,[[_5,_6,_7,[_8,_9,_10,_11,_12,[_13,0]]]]]),
        writeq(call=Data2),nl,
        T2 is cputime,
                     Data2,!,
        T2t is cputime-T2,
        writeq(succ=   Data2),nl,
        write(T2t='seconds '),nl.

write_line:- write('*******************************'),nl.      

%% ひとつ assert されるごとにヒープエリア　50セルを消費します
mk_unit(N,data(N,A,N,atest(A),[B,[[C,[D],A,[E,F,_,A,A,[A,N]]]]]) ):-
        A is N^2,B is N*2,C is N*3,D is N*4,E is N*5,F is N*6.

:- s_mode(_,off).
