% |
% This file contains the source code for first optimization, |
% which implements the algorithm to eliminate backtracking for |
% non-interacting processes. |
% |
:- import updat/1 from updates. |
:- import append/3 from basics. |
% define directive opt1_trans |
opt1_trans(File_ctr) :- |
in_opt(File_ctr,File1), |
see(File1), |
remove_upd, |
insert_upd(Preds), |
remove_graph, |
opt_read_and_create_graph(File1), |
seen, |
see(File1), |
out_opt(File_ctr,FileOut), |
unix('rm -f FileOut 2>/dev/null', R1), |
tell(FileOut), |
opt_read_and_compile(File1,FileOut), |
seen, told. |
% parse rules from object file repeatedly |
% to create dependency graph |
opt_read_and_create_graph(FileIn) :- |
read(Term), |
( |
(Term == end_of_file) -> true |
; |
opt_read_rule(Term,FileIn), |
opt_read_and_create_graph(FileIn) ). |
% read transaction base object file |
opt_read_and_compile(FileIn,FileOut) :- |
read(Term), |
( |
(Term == end_of_file) -> true |
; |
opt_read_and_write_rule(Term,FileIn,FileOut), |
opt_read_and_compile(FileIn,FileOut) ). |
% translation of a transaction clause |
opt_read_rule(':-'(trans(Lhs),Rhs),_) :- |
Lhs =..Lname, |
Lname = [Name|_], |
insert_edge(Name, Rhs). |
opt_read_rule(':-'(Lhs,Rhs),_). |
% write optimized transaction rules |
opt_read_and_write_rule(':-'(trans(Lhs),Rhs),_,_) :- |
write(trans(Lhs)), |
write(' :- '), |
remove_dep, |
optI(Rhs, PRhs), |
write(PRhs), |
write('.'), nl. |
opt_read_and_write_rule(':-'(Lhs,Rhs),_,_) :- |
write(Lhs), |
write(' :- '), |
write(Rhs), |
write('.'), nl. |
% optimization is performed only on isolated processes |
optI(isolate(P), isolate(R)) :- optN(P, R). |
optI(isolate1(P), isolate1(R)) :- optN(P, R). |
optI(seq(L), seq(L1)) :- optI_list(L, L1). |
optI(conc(L), conc(L1)) :- optI_list(L, L1). |
optI(P, P). |
optN(isolate(P), isolate(R)) :- optN(P, R). |
optN(isolate1(P), isolate1(R)) :- optN(P, R). |
optN(seq(L), seq(L1)) :- optN_list(L, L1). |
optN(conc(L), conc(L1)) :- check_interact(L), |
dep(1), |
optI_list(L, L1). |
optN(conc(L), conc1(L1)) :- optN_list(L, L1). |
optN(P, P). |
% check for interaction |
check_interact([]). |
check_interact(L) :- L = [Head|Tail], |
P = Head, |
remove_dep, |
check_tail(P, Tail), |
not(dep(1)), |
check_interact(Tail). |
check_interact(L) :- dep(1). |
check_tail(P, []). |
check_tail(P, Tail) :- Tail = [H1|Tail1], |
(interact(P, H1), |
not(dep(1)), |
assert(dep(1)) |
; |
check_tail(P, Tail1)). |
optI_list([], []). |
optI_list(L, L1) :- L = [H0|Tail0], |
L1 = [H1|Tail1], |
optI(H0, H1), |
optI_list(Tail0, Tail1). |
optN_list([], []). |
optN_list(L, L1) :- L = [H0|Tail0], |
L1 = [H1|Tail1], |
optN(H0, H1), |
optN_list(Tail0, Tail1). |
% build dependency graph |
insert_edge(Name, Rhs) :- appears(Rhs, X), |
not(edge(Name, X)), |
assert(edge(Name, X)), |
fail. |
insert_edge(Name, Rhs). |
insert_upd(Preds) :- updat(Preds), |
Preds =..Lpreds, |
Lpreds = [Name|_], |
assert(upd(Name)), fail. |
insert_upd(Preds). |
% edges between predicate in Head of rules |
% and predicates or elementary op in rule boby |
appears(conc(L), X) :- L = [Head|_], |
appears(Head, X). |
appears(conc(L), X) :- L = [_|Tail], |
appears(conc(Tail), X). |
appears(seq(L), X) :- L = [Head|_], |
appears(Head, X). |
appears(seq(L), X) :- L = [_|Tail], |
appears(seq(Tail), X). |
appears(isolate1(E), X) :- !, appears(E, X). |
appears(isolate(E), X) :- !, appears(E, X). |
appears(ins(X), Y) :- !, X =..Pred, |
Pred = [Name|_], |
Y = ins(Name). |
appears(del(X), Y) :- !, X =..Pred, |
Pred = [Name|_], |
Y = del(Name). |
appears(P, Y) :- P =..Pred, |
Pred = [Name|_], |
not(Name = conc), |
not(Name = seq), |
not(Name = isolate), |
not(Name = isolate1), |
atom(Name), |
Y = Name. |
% check if nodes in dependency graph are connected |
reachable(P, P). |
reachable(P, Q) :- edge(P, Q). |
reachable(P, Q) :- edge(P, R), reachable(R, Q). |
% definition for query sets |
qref(Q, Q) :- Q =..Pred, |
Pred = [Name|_], |
upd(Name). |
qref(E, Q) :- appears(E, P), reachable(P, Q), upd(Q). |
% definition for insert sets |
iref(ins(Q), Q). |
iref(E, Q) :- appears(E, P), reachable(P, ins(Q)). |
% definition for delete sets |
dref(del(Q), Q). |
dref(E, Q) :- appears(E, P), reachable(P, del(Q)). |
% definition of interaction in the graph |
interact1(P, Q) :- qref(P, B), iref(Q, B). |
interact1(P, Q) :- qref(P, B), dref(Q, B). |
interact1(P, Q) :- iref(P, B), dref(Q, B). |
interact(P, Q) :- interact1(P, Q). |
interact(P, Q) :- interact1(Q, P). |
independent(P, Q) :- not(interact(P, Q)). |
add_isolate([], []). |
add_isolate(L, L1) :- L = [H0|Tail0], |
L1 = [H1|Tail1], |
H1 = isolate(H0), |
add_isolate(Tail0, Tail1). |
% remove any work tuples before starting optimization |
remove_upd :- retract(upd(X)), fail. |
remove_upd. |
% delete dependency graph |
remove_graph :- retract(edge(X, Y)), fail. |
remove_graph. |
remove_dep :- retract(dep(1)). |
remove_dep. |
remove(K) :- retract(dep(K)). |
remove(K). |
% create object file name used as input |
in_opt(FileIn,FileOut) :- |
name(FileIn,NameIn), |
append(NameIn,".ctr.o",NameOut), |
name(FileOut,NameOut). |
% create optimized file name used as output |
out_opt(FileIn,FileOut) :- |
name(FileIn,NameIn), |
append(NameIn,".opt1.o",NameOut), |
name(FileOut,NameOut). |
opt_insert_file(FileName) :- |
seeing(X), |
see(FileName), |
opt_read_and_add_line, |
see(X). |
opt_read_and_add_line :- |
read(Line), |
( |
(Line == end_of_file) -> true |
; |
assert(Line), |
opt_read_and_add_line ). |
edge(dummy, dummy) :- fail. |
modifiable(dummy) :- fail. |
upd(dummy) :- fail. |
dep(dummy) :- fail. |