1 % (c) 2016-2019 Lehrstuhl fuer Softwaretechnik und Programmiersprachen,
2 % Heinrich Heine Universitaet Duesseldorf
3 % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html)
4
5 :- module(b_operation_cache, [ %project_in_state/3,
6 %operation_computed/4,
7 compute_operation_on_expanded_store_cache/5,
8 print_op_cache/0
9 ]).
10
11
12 :- use_module(module_information).
13 :- module_info(group,animator).
14 :- module_info(description,'This module caches B operation results on projected states.').
15
16
17 :- use_module(extension('counter/counter')). % op_cache_id counter
18
19 b_operation_cache_startup :- % call once at startup to ensure all counters exist
20 counter_init,
21 new_counter(op_cache_id).
22
23 :- use_module(eventhandling,[register_event_listener/3]).
24
25 :- register_event_listener(startup_prob,b_operation_cache_startup,
26 'Initialise Statespace Counters.').
27 :- register_event_listener(clear_specification,reset_b_operation_cache,
28 'Reset Operation Cache.').
29 :- register_event_listener(change_of_animation_mode,reset_b_operation_cache,
30 'Reset Operation Cache.').
31 % TO DO: also reset if maxNrOfEnablingsPerOperation changed ?
32
33 :- use_module(error_manager).
34 :- use_module(bmachine,[b_get_operation_normalized_read_write_info/3]).
35
36 :- dynamic operation_read_projection_cache/2.
37 reset_b_operation_cache :-
38 retractall(operation_read_projection_cache(_,_)),
39 retractall(operation_computed(_,_,_,_)),
40 retractall(operation_cached_results(_,_,_,_)),
41 reset_counter(op_cache_id).
42
43 % project the in-state for an operation onto the relevant variables
44 project_in_state(InState,OpName,ProjectedInState ) :-
45 % TO DO: statically pre-compute which operations are worthwhile for this treatment
46 operation_read_projection_cache(OpName,ProjVars),
47 !,
48 ProjVars \= no_caching,
49 (re_project_state(ProjVars,InState,Res) -> ProjectedInState=Res
50 ; add_internal_error('Re-Projection failed: ',re_project_state(ProjVars,InState,_)),
51 ProjectedInState = InState).
52 %project_in_state(_,OpName,_ ) :- \+ worthwhile_to_cache(OpName),!,
53 % assert(operation_read_projection_cache(OpName,no_caching)),
54 % fail.
55 project_in_state(InState,OpName,ProjectedInState ) :-
56 b_get_operation_normalized_read_write_info(OpName,ReadVariables,_WrittenVariables),
57 project_state_onto_vars(InState,ReadVariables,ProjVarsInOrder,RelevantState,0,NrDeleted),
58 (NrDeleted>0
59 -> assert(operation_read_projection_cache(OpName,ProjVarsInOrder)),
60 %print(proj(OpName,PredResult,RelevantState)),nl,
61 ProjectedInState = RelevantState
62 ; assert(operation_read_projection_cache(OpName,no_caching)),
63 print(not_caching(OpName)),nl,
64 fail).
65
66
67 % check if caching is worthwhile for this operation
68 %worthwhile_to_cache(OpName) :-
69 % b_get_operation_normalized_read_write_info(OpName,ReadVariables,WrittenVariables),
70 % length(ReadVariables,NrRV),
71 % bmachine:b_machine_statistics(variables,NrVars),
72 % bmachine:b_machine_statistics(constants,NrConstants),
73 % Perc is (NrRV*100) // (NrVars+NrConstants),
74 % length(WrittenVariables,NrWV),
75 % format('Analyzing ~w, ~w %, read: ~w, written: ~w, tot vars: ~w, tot cst: ~w~n (read: ~w)~n',[OpName,Perc,NrRV,NrWV,NrVars,NrConstants,ReadVariables]),
76 % Perc < 95. % maybe provide as preference
77
78 :- use_module(library(ordsets),[ord_member/2]).
79 %is_read(ReadVariables,bind(Var,_)) :- ord_member(Var,ReadVariables).
80
81 % a variation of split_list which also returns a list of predicate results
82 % with re_project_state(L,ProjVarsInOrder,A) : we can split another list using the same pattern
83
84 project_state_onto_vars([],_,[],[],Acc,Acc).
85 project_state_onto_vars([Elem|Rest],ReadVariables,ProjVars,A,NrDelAcc,NrDel) :- Elem = bind(Var,_),
86 (ord_member(Var,ReadVariables)
87 -> ProjVars=[Var|PT], A=[Elem|AR], ND1=NrDelAcc
88 ; ProjVars=PT, A=AR, ND1 is NrDelAcc+1),
89 project_state_onto_vars(Rest,ReadVariables,PT,AR,ND1,NrDel).
90
91 % project state(VarsInOrder,State,ProjectedState)
92 % faster than project_state_onto_vars
93 re_project_state([],_,[]).
94 re_project_state([V|PT],[Elem|Rest],A) :- Elem = bind(Var,_),
95 (V==Var -> A=[Elem|AR],re_project_state(PT,Rest,AR)
96 ; re_project_state2(V,PT,Rest,A)).
97
98 re_project_state2(V,PT,[Elem|Rest],A) :- Elem = bind(Var,_),
99 (V==Var -> A=[Elem|AR],re_project_state(PT,Rest,AR)
100 ; re_project_state2(V,PT,Rest,A)).
101
102 % -------------------------------
103
104 :- use_module(hashing).
105 :- use_module(state_packing).
106
107 :- dynamic operation_computed/4, operation_cached_results/4.
108
109 % return Hash and check if operation computed
110 % TO DO: do not hash constants if single value exists ?
111 operation_was_computed(OpName,State,PackedState,Hash,Res) :-
112 pack_values(State,PackedState),
113 hashing:my_term_hash(op(OpName,PackedState),Hash),
114 %terms:term_hash(op(OpName,PackedState),[range(smallint),algorithm(sdbm),depth(infinite),if_var(ignore)],Hash),
115 (operation_computed(Hash,OpName,PackedState,ID) -> Res = ID
116 ; Res= false).
117
118 get_new_operation_computed_id(OpName,PackedState,Hash,ID) :-
119 inc_counter(op_cache_id,ID),
120 assert(operation_computed(Hash,OpName,PackedState,ID)).
121
122 :- use_module(probsrc(b_interpreter),[b_execute_top_level_operation_update/5]).
123 % this is used when get_preference(try_operation_reuse,full)
124 compute_operation_on_expanded_store_cache(OpName,Operation,InState,NewState,PathInfo) :-
125 %print(comp(OpName,InState)),nl,
126 project_in_state(InState,OpName,ProjInState),
127 !,
128 %print(proj(OpName,ProjInState)),nl,
129 operation_was_computed(OpName,ProjInState,PackedState,Hash,ID),
130 %print(o(Hash,ID,OpName)),nl,
131 (ID \= false
132 -> %print(cache(OpName,ID)),nl,
133 %print('+'),
134 %hit_profiler:add_hit(operation_reused,OpName),
135 operation_cached_results(ID,Operation,PackedNewState,PathInfo),
136 unpack_values(PackedNewState,NewState)
137 ; get_new_operation_computed_id(OpName,PackedState,Hash,NewID),
138 %print('-'),
139 %hit_profiler:add_hit(operation_cache_computation,OpName),
140 b_execute_top_level_operation_update(OpName,Operation,ProjInState,NewState,PathInfo),
141 pack_values(NewState,PackedNewState),
142 assert(operation_cached_results(NewID,Operation,PackedNewState,PathInfo))
143 ).
144 compute_operation_on_expanded_store_cache(OpName,Operation,InState,NewState,PathInfo) :-
145 %print(not_caching(OpName)),nl,
146 %hit_profiler:add_hit(operation_not_cached,OpName),
147 b_interpreter:b_execute_top_level_operation_update(OpName,Operation,InState,NewState,PathInfo).
148
149
150 % small utility code to analyze hash collisions:
151 % b_operation_cache:ahc.
152 :- public ahc/0.
153 ahc :- operation_computed(Hash,OpName,State,ID),
154 operation_computed(Hash,OpName2,State2,ID2),
155 ID2 > ID,
156 format('Hash collision: ~w~n ~w:~w:~w~n ~w:~w:~w~n~n',[Hash,OpName,State,ID,OpName2,State2,ID2]),
157 fail.
158 ahc.
159
160 :- use_module(translate,[translate_bstate_limited/2, translate_event_with_limit/3]).
161 :- use_module(debug,[debug_mode/1]).
162 % b_operation_cache:print_op_cache
163 print_op_cache :- \+ operation_computed(_,_,_,_),!. % print nothing
164 print_op_cache :- operation_read_projection_cache(OpName,ProjVars),
165 format('Operation ~w cached onto: ~w~n',[OpName,ProjVars]),fail.
166 print_op_cache :- operation_read_projection_cache(OpName,_),
167 findall(ID,b_operation_cache:operation_computed(_Hash,OpName,_,ID),Ls), length(Ls,Nr),
168 format('Next-state-calls for ~w: ~w~n',[OpName,Nr]),fail.
169 print_op_cache :-
170 findall(ID,b_operation_cache:operation_computed(_Hash,_Op,_,ID),Ls), length(Ls,Nr),
171 format('Total Number of Next-state-calls: ~w~n',[Nr]),fail.
172 print_op_cache :- debug_mode(on),
173 print('Local Operation Cache Info:'),nl,
174 operation_computed(_Hash,OpName,PackedState,ID),
175 format('~nNode ID = ~w, Operation = ~w~n',[ID,OpName]),
176 unpack_values(PackedState,State), translate_bstate_limited(State,NodeDesc),
177 format(' projected state : ~w~n',[NodeDesc]),
178 operation_cached_results(ID,Operation,PackedNewState,_PathInfo),
179 translate_event_with_limit(Operation,100,OpStr),
180 unpack_values(PackedNewState,NewState), translate:translate_bstate_limited(NewState,UpdateStr),
181 format(' ~w -upd-> ~w~n',[OpStr,UpdateStr]),
182 fail.
183 print_op_cache :- ahc,print('----------'),nl.
184
185 % ----------------------
186 % DOT RENDERING (not yet finished)
187
188 %op_cache_node(ID,OpName,NodeDesc,Shape,Style,Color) :- Shape=box, Style=solid, Color=blue,
189 % operation_computed(_Hash,OpName,PackedState,ID),
190 % unpack_values(PackedState,State), translate_bstate_limited(State,NodeDesc).
191 %:- use_module(probsrc(dot_graph_generator),[gen_dot_graph/6]).
192 % Predicates for creating a dependency graph
193 %tcltk_operation_cache_graph(File) :- gen_dot_graph(File,b_operation_cache,op_cache_node,cbc_dependence_trans_predicate,none,none).
194