1 | % (c) 2009-2013 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 | ||
6 | :- module(log_analyser,[set_log_file_to_analyse/1, analyse_log/3, analyse_log/0, set_row_identifier/1, | |
7 | check_log/1]). | |
8 | ||
9 | ||
10 | % to do: use argv to determine which log file(s) are to be included | |
11 | :- use_module(tools). | |
12 | :- use_module(error_manager). | |
13 | :- use_module(library(lists)). | |
14 | ||
15 | :- use_module(module_information,[module_info/2]). | |
16 | :- module_info(group,misc). | |
17 | :- module_info(description,'A small tool to generate Excel or Gnuplot data and scripts to analyse data generated by probcli when model checking with logging (-l).'). | |
18 | ||
19 | :- dynamic benchmark/1, benchmark/3, row_identifier/1, group/1. | |
20 | ||
21 | assert_group(G) :- group(G) -> true ; assert(group(G)). | |
22 | ||
23 | mc_entry(BenchT,TIME,MCTime) :- mc_entry(BenchT,TIME,MCTime,_REV). | |
24 | mc_entry(BenchT,TIME,FullWallTime,rev(REV,FOptions)) :- | |
25 | model_check(Now,_,_MCTime,_Res,_TotRun,TotWall), | |
26 | loading(Now,B,_StartRun,StartWall), | |
27 | FullWallTime is TotWall - StartWall, % assumes nothing else done | |
28 | version(Now,_V1,_V2,_V3,_V4,REV,_LASTCHANGED), | |
29 | options(Now,Options), filter_options(Options,FOptions), | |
30 | %date(Now,datime(Year,Month,Day,_,_)), | |
31 | TIME = Now, %is Now // 100, | |
32 | get_tail_filename(B,BenchT). | |
33 | ||
34 | init :- retractall(benchmark(_)), print('Benchmarks: '), | |
35 | setof(B,Date^Time^mc_entry(B,Date,Time),Bench), | |
36 | sort(Bench,SB), | |
37 | print(SB),nl, | |
38 | member(B1,SB), | |
39 | assert(benchmark(B1)),fail. | |
40 | init :- retractall(benchmark(_,_,_)),benchmark_group(Group,Benchmark,Name), | |
41 | (benchmark(Benchmark) -> true ; print('### No entry for : '), print(Benchmark),nl,fail), | |
42 | assert(benchmark(Benchmark,Group,Name)), assert_group(Group), | |
43 | fail. | |
44 | init :- benchmark(Benchmark), \+ benchmark_group(_,Benchmark,_), | |
45 | print('* No group for: '), print(Benchmark),nl, | |
46 | assert(benchmark(Benchmark,unknown,Benchmark)), assert_group(unknown), fail. | |
47 | init :- retractall(row_identifier(_)), | |
48 | use_for_row_identifier(timestamp), print('Timestamps: '), | |
49 | setof(D,B^Time^mc_entry(B,D,Time),Dates), | |
50 | sort(Dates,SB), | |
51 | print(SB),nl, | |
52 | member(D1,SB), | |
53 | assert(row_identifier(D1)),fail. | |
54 | init :- use_for_row_identifier(revision), print('Revisions: '), | |
55 | setof(Rev,B^D^Time^mc_entry(B,D,Time,Rev),Revs), | |
56 | sort(Revs,SB), | |
57 | print(SB),nl, | |
58 | member(D1,SB), | |
59 | assert(row_identifier(D1)),fail. | |
60 | init. | |
61 | ||
62 | ||
63 | filter_options([],[]). | |
64 | filter_options([H|T],R) :- | |
65 | (interesting_option(H,HH) -> R=[HH|RT] %prob_cli:recognised_option(HH,H),R=[HH|RT] | |
66 | ; R=RT), | |
67 | filter_options(T,RT). | |
68 | interesting_option(depth_first,df). | |
69 | interesting_option(breadth_first,bf). | |
70 | interesting_option(comment(C),C). | |
71 | interesting_option(set_pref('OPERATION_REUSE',T),op_reuse) :- is_true(T). | |
72 | interesting_option(set_pref('USE_PO',T),no_po) :- is_false(T). | |
73 | interesting_option(set_pref('SYMMETRY_MODE',hash),hash). | |
74 | interesting_option(set_pref('SYMMETRY_MODE',nauty),nauty). | |
75 | interesting_option(set_pref('SYMMETRY_MODE',flood),flood). | |
76 | interesting_option(set_pref('SYMBOLIC',T),symbolic) :- is_true(T). | |
77 | %interesting_option(no_deadlocks,nodead). | |
78 | %interesting_option(no_invariant_violations,noinv). | |
79 | %interesting_option(set_pref(PREF,PREFVAL),pref(PREF,PREFVAL)). | |
80 | ||
81 | is_true('TRUE'). is_true(true). | |
82 | is_false('FALSE'). is_false(false). | |
83 | ||
84 | % determine what is used to group rows | |
85 | :- dynamic use_for_row_identifier/1. | |
86 | use_for_row_identifier(timestamp). | |
87 | %use_for_row_identifier(revision). | |
88 | ||
89 | set_row_identifier(ID) :- (ID=timestamp; ID=revision),!, | |
90 | retractall(use_for_row_identifier(_)), | |
91 | assert(use_for_row_identifier(ID)). | |
92 | set_row_identifier(ID) :- add_error(log_analyser,'Illegal Row Identifier: ',ID). | |
93 | ||
94 | get_mc_time_for_row_identifier(Benchmark,ID,MCTime) :- use_for_row_identifier(timestamp), | |
95 | ID=TimeStamp, | |
96 | mc_entry(Benchmark,TimeStamp,MCTime,_Rev). | |
97 | get_mc_time_for_row_identifier(Benchmark,ID,MCTime) :- use_for_row_identifier(revision), | |
98 | ID=Revision, | |
99 | mc_entry(Benchmark,_TimeStamp,MCTime,Revision). | |
100 | ||
101 | :- public p/0. | |
102 | p :- init, print_normal_table. | |
103 | ||
104 | print_normal_table :- print_header, | |
105 | print_row_identifier_header, | |
106 | benchmark(_B,_,BN), print_cell(BN), | |
107 | fail. | |
108 | print_normal_table :- nl, | |
109 | row_identifier(D), | |
110 | print_row(D), | |
111 | fail. | |
112 | print_normal_table :- nl. | |
113 | ||
114 | print_transposed_excel_table :- print_header, | |
115 | print_cell('Revision'), row_identifier(D), print_row_identifier1(D),fail. | |
116 | print_transposed_excel_table :- nl, | |
117 | print_cell('Benchmark/Options'), row_identifier(D), print_row_identifier2(D),fail. | |
118 | print_transposed_excel_table :- nl, | |
119 | group(G), print_cell(G),nl, | |
120 | print_message(treating_group(G)), | |
121 | benchmark(B,G,BN), print_cell(BN), | |
122 | print_benchmark_line(B), | |
123 | fail. | |
124 | print_transposed_excel_table :- nl. | |
125 | ||
126 | print_benchmark_line(B) :- row_identifier(RowID), print_mc_time_cell(B,RowID),fail. | |
127 | print_benchmark_line(_) :- nl. | |
128 | ||
129 | print_row(RowID) :- print_row_identifier(RowID), | |
130 | benchmark(B,_,_), print_mc_time_cell(B,RowID), | |
131 | fail. | |
132 | print_row(_) :- nl. | |
133 | ||
134 | print_mc_time_cell(B,RowID) :- | |
135 | (get_mc_time_for_row_identifier(B,RowID,MCTime) -> print_cell(MCTime) ; print_cell('??')). | |
136 | ||
137 | print_row_identifier_header :- use_for_row_identifier(revision),!, | |
138 | print_cell('Revision'), print_cell('Options'). | |
139 | print_row_identifier_header :- print_cell('Timestamp'). | |
140 | ||
141 | print_row_identifier1(rev(ID,_Options)) :- print_cell(ID),!. | |
142 | print_row_identifier1(X) :- print_row_identifier(X). | |
143 | print_row_identifier2(rev(_ID,Options)) :- print_cell(Options),!. | |
144 | print_row_identifier2(X) :- print_row_identifier(X). | |
145 | ||
146 | print_row_identifier(rev(ID,Options)) :- use_for_row_identifier(revision),!, | |
147 | print_cell(ID),print_cell(Options). | |
148 | print_row_identifier(TimeStamp) :- | |
149 | (date(TimeStamp,datime(Year,Month,Day,Hour,Minutes,Seconds)) | |
150 | -> RealTime is Seconds + Minutes*60 + Hour*60*60 + | |
151 | Day*24*60*60 + Month*31*24*60*60 + (Year-2008)*12*31*24*60*60, | |
152 | print_cell(RealTime) | |
153 | ; print_cell(TimeStamp), tools:print_error(unknown(TimeStamp)) | |
154 | ). | |
155 | ||
156 | print_cell(X) :- var(X),!,print('_VARIABLE_'), print_sep. | |
157 | print_cell([H|T]) :- !, print('"'),print_list([H|T]), print('"'), print_sep. | |
158 | print_cell(X) :- print(X), print_sep. | |
159 | ||
160 | print_list([]). | |
161 | print_list([H|T]) :- print(H), print_list(T). | |
162 | ||
163 | print_gnuplot_script :- data_file(F), | |
164 | format('set xtics 1,1~Nset style data linespoints~Nset title ""~Nset grid ytics~Nset terminal postscript eps enhanced~Nset output "~p.ps"~N',[F]), | |
165 | % set term aqua | |
166 | print('plot '), | |
167 | findall(BN,benchmark(_B,_,BN),Benchs), | |
168 | nth1(Nr,Benchs,BB), | |
169 | (Nr>1 -> print(', \\'),nl ; true), | |
170 | print_data_file, | |
171 | N1 is Nr+1, | |
172 | print('using 1:'), print(N1), print(' title "'),print(BB), print('"'), | |
173 | fail. | |
174 | print_gnuplot_script :- nl. | |
175 | ||
176 | print_data_file :- data_file(F), print('"'),print(F),print('" '). | |
177 | ||
178 | ||
179 | :- dynamic log_file/1. | |
180 | log_file('../log/puzzle.log'). | |
181 | ||
182 | set_log_file_to_analyse(F) :- retractall(log_file(_)), assert(log_file(F)), | |
183 | split_filename(F,Base,_Extension), | |
184 | data_file_extension(DExt), | |
185 | string_concatenate(Base,DExt,DF), | |
186 | print_message(data_file(DF)), | |
187 | retractall(data_file(_)), assert(data_file(DF)), | |
188 | string_concatenate(Base,'.plot',PF), | |
189 | print_message(script_file(PF)), | |
190 | retractall(script_file(_)), assert(script_file(PF)). | |
191 | ||
192 | :- dynamic data_file/1. | |
193 | data_file('../log/puzzle.data'). | |
194 | ||
195 | :- dynamic script_file/1. | |
196 | script_file('../log/puzzle.plot'). | |
197 | ||
198 | ||
199 | :- dynamic for_gnuplot/0. | |
200 | for_gnuplot. | |
201 | ||
202 | print_header :- for_gnuplot,!,print('# '). | |
203 | print_header. | |
204 | ||
205 | print_sep :- for_gnuplot,!,print('\t'). % for gnuplot | |
206 | print_sep :- print(', '). % for Excel CSV | |
207 | ||
208 | ||
209 | data_file_extension(Ext) :- | |
210 | (for_gnuplot -> Ext = '.data' ; Ext = '.csv'). | |
211 | ||
212 | % ------------------- | |
213 | ||
214 | analyse_log(F,RowID,ForGnuPlot) :- set_row_identifier(RowID), | |
215 | retractall(for_gnuplot), | |
216 | (ForGnuPlot=true -> assert(for_gnuplot) ; true), | |
217 | set_log_file_to_analyse(F), | |
218 | analyse_log. | |
219 | ||
220 | :- dynamic benchmark_group/3. | |
221 | ||
222 | analyse_log :- log_file(LF), consult_without_redefine_warning(LF), | |
223 | print_message('Initialising'), | |
224 | init, | |
225 | data_file(F), | |
226 | print_message('Generating Table'), | |
227 | tell(F), | |
228 | (for_gnuplot -> print_normal_table ; print_transposed_excel_table), | |
229 | told, | |
230 | print_message('Finished Generating Table'), | |
231 | (for_gnuplot | |
232 | -> script_file(SF), | |
233 | tell(SF), | |
234 | print_gnuplot_script, | |
235 | told, | |
236 | print('Now run "gnuplot '), print(SF), print('"'),nl, | |
237 | print(' and then open "'),print(F),print('.ps"'),nl % we could execute it also in Prolog | |
238 | ; print('Now open "'), print(F), print('" using Excel'),nl | |
239 | ). | |
240 | ||
241 | ||
242 | consult_without_redefine_warning(File) :- | |
243 | prolog_flag(redefine_warnings, Old, off), | |
244 | (% load in dynamic mode: so that we can retract later | |
245 | my_consult(File) | |
246 | -> OK=true ; OK=false), | |
247 | prolog_flag(redefine_warnings, _, Old), | |
248 | (OK=true -> true ; | |
249 | add_error_and_fail(bmachine,'Consulting of File failed: ',File)). | |
250 | ||
251 | my_consult(File) :- on_exception(error(existence_error(_,_),_), | |
252 | load_files(File,[compilation_mode(assert_all)]), | |
253 | add_error_fail(my_consult,'File does not exist: ',File)). | |
254 | ||
255 | % ------------------------ | |
256 | ||
257 | % a version suitable for analysing the Siemens RuleBase validation output | |
258 | % run with probcli -p CLPFD TRUE -p TIME_OUT 5000 *.v -l all.log -init -expcterr setup_constants_fails | |
259 | :- dynamic loading/4. | |
260 | :- dynamic error_occurred/2, loading_failed/4, expected_error_did_not_occur/2. | |
261 | :- dynamic start_animation/3, finished_processing/2. | |
262 | ||
263 | check_log(F) :- consult_without_redefine_warning(F), | |
264 | print('File'), print_sep, print('Result'), print_sep, | |
265 | print('Loading time'), print_sep, print('(Walltime)'), print_sep, | |
266 | print('Checking time'), print_sep, print('(Walltime)'), nl, | |
267 | lookup(loading(NOW,Filename,StartTime,StartWTime)),nl, | |
268 | get_tail_filename(Filename,Tail), | |
269 | print(Tail), print_sep, | |
270 | (lookup(error_occurred(NOW,parse_error)) -> print('PARSE ERROR') | |
271 | ; lookup(error_occurred(NOW,type_error)) -> print('TYPE ERROR') | |
272 | ; lookup(error_occurred(NOW,time_out)) -> print('TIME_OUT') | |
273 | ; lookup(error_occurred(NOW,cbc_assertions_time_out)) -> print('TIME_OUT') | |
274 | ; lookup(loading_failed(NOW,Filename,_,_)) -> print('OTHER LOAD ERROR') | |
275 | ; lookup(error_occurred(NOW,cbc_assertions)) | |
276 | -> print('** KO **') % print('*** COUNTER EXAMPLE FOUND ***') | |
277 | ; lookup(cbc_assertions_finished(NOW,no_counterexample_found,_,_)) | |
278 | -> print('OK (ENUM WARNING)') | |
279 | % TO DO: also register if b_global_sets:unfixed_deferred_set(_) TRUE or not | |
280 | % ; lookup(cbc_assertions_finished(NOW,no_counterexample_exists,_,_) | |
281 | % \+ b_global_sets:unfixed_deferred_set(_) | |
282 | % -> print('PROOF') | |
283 | ; print('OK') | |
284 | ), | |
285 | print_times(NOW,StartTime,StartWTime), | |
286 | fail. | |
287 | check_log(_) :- nl. | |
288 | ||
289 | lookup(Fact) :- on_exception(error(existence_error(_,_),_),call(Fact),fail). | |
290 | ||
291 | print_times(NOW,StartTime,StartWTime) :- | |
292 | start_animation(NOW,T1,W1),!, | |
293 | print_sep,print_time(loading,StartTime,StartWTime,T1,W1),print_sep, | |
294 | (lookup(cli_start_initialisation_failed(NOW,T2,W2)) | |
295 | -> print_time(checking_OK,T1,W1,T2,W2) % no counter-example found | |
296 | ; lookup(cbc_assertions_finished(NOW,_,T2,W2)) | |
297 | -> print_time(checking,T1,W1,T2,W2) % counter-example found | |
298 | ; lookup(finished_processing(NOW,T2,W2)) | |
299 | -> print_time(checking_ERR,T1,W1,T2,W2) % other error | |
300 | ). | |
301 | print_times(NOW,StartTime,StartWTime) :- | |
302 | lookup(loading_failed(NOW,_Filename,T1,W1)),!, | |
303 | print_sep,print_time(loading_failure,StartTime,StartWTime,T1,W1). | |
304 | ||
305 | ||
306 | print_time(_Msg,Start,WStart,End,WEnd) :- | |
307 | %print(Msg), print_sep, | |
308 | T is End-Start, print(T), print(' ms'), print_sep, | |
309 | W is WEnd-WStart, print(W), print(' ms'). | |
310 | ||
311 | %check_error_occurred(NOW,Err) :- on_exception(error(existence_error(_,_),_), | |
312 | % error_occurred(NOW,Err), fail). | |
313 | %check_loading_failed(NOW,Err) :- on_exception(error(existence_error(_,_),_), | |
314 | % loading_failed(NOW,Err), fail). | |
315 | %check_expected_error_did_not_occur(NOW,Err) :- on_exception(error(existence_error(_,_),_), | |
316 | % expected_error_did_not_occur(NOW,Err), fail). | |
317 | ||
318 | /* | |
319 | Desired output: | |
320 | <Prob> | |
321 | <resultat> OK ou KO </resultat> | |
322 | <commentaires> aficher les contradications </commentaires> | |
323 | <temps> temps de traitement </temps> | |
324 | </Prob> | |
325 | */ |