501 lines
16 KiB
Text
501 lines
16 KiB
Text
|
(*
|
||
|
V2 +
|
||
|
In this example we model is a falttering of the example toy.
|
||
|
we may add some lifecycle management.
|
||
|
*)
|
||
|
|
||
|
type core = C1| C2| C3| C4
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
(* An automaton to model the lifecycyle of a component *)
|
||
|
node lifecycle(change, kill, fifoEmpty :bool) returns(started, unbound:bool; c_start, c_connect, c_stop, c_disconnect:bool)
|
||
|
let
|
||
|
automaton
|
||
|
state STOPPED do
|
||
|
started = false;
|
||
|
unbound = true;
|
||
|
(c_start, c_connect, c_stop, c_disconnect)=(change, change, false, false);
|
||
|
until change then STARTED
|
||
|
|
||
|
|
||
|
state STARTED do
|
||
|
started = true;
|
||
|
unbound = false;
|
||
|
(c_start, c_connect, c_stop, c_disconnect)=(false, false, (change&fifoEmpty)or(kill),(change or kill));
|
||
|
until change & not fifoEmpty then STOPPING
|
||
|
| change & fifoEmpty then STOPPED
|
||
|
| kill then STOPPED
|
||
|
|
||
|
state STOPPING do
|
||
|
started = true;
|
||
|
unbound = true;
|
||
|
(c_start, c_connect, c_stop, c_disconnect)=(false, change, (fifoEmpty or kill), false);
|
||
|
until fifoEmpty or kill then STOPPED
|
||
|
| change then STARTED
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
(* An atamaton to model the state of a FIFIO *)
|
||
|
node fifo(f:bool) returns (full:bool)
|
||
|
let
|
||
|
automaton
|
||
|
state EMPTY do
|
||
|
full = false;
|
||
|
until f then FULL
|
||
|
state FULL do
|
||
|
full = true;
|
||
|
until not f then EMPTY
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
|
||
|
(* defines the position of a task *)
|
||
|
(* It has two boolean inputs to encode 4 possible outgoing transitions *)
|
||
|
|
||
|
node position(a, b :bool)returns(position:core; c_mig1, c_mig2, c_mig3, c_mig4:bool)
|
||
|
|
||
|
(* !a!b go to the next in the numerical order
|
||
|
!ab to the second
|
||
|
a!b to the last *)
|
||
|
let
|
||
|
|
||
|
automaton
|
||
|
state C1 do
|
||
|
position=C1;
|
||
|
(c_mig1, c_mig2, c_mig3, c_mig4)=(false, not a & not b, not a & b, a & not b);
|
||
|
until not a & not b then C2
|
||
|
| not a & b then C3
|
||
|
| a & not b then C4
|
||
|
|
||
|
state C2 do
|
||
|
position=C2;
|
||
|
(c_mig1, c_mig2, c_mig3, c_mig4)=(a & not b, false, not a & not b, not a & b);
|
||
|
until not a & not b then C3
|
||
|
| not a & b then C4
|
||
|
| a & not b then C1
|
||
|
|
||
|
state C3 do
|
||
|
position=C3;
|
||
|
(c_mig1, c_mig2, c_mig3, c_mig4)=( not a & b, a & not b, false, not a & not b);
|
||
|
until not a & not b then C4
|
||
|
| not a & b then C1
|
||
|
| a & not b then C2
|
||
|
|
||
|
|
||
|
state C4 do
|
||
|
position=C4;
|
||
|
(c_mig1, c_mig2, c_mig3, c_mig4)=( not a & not b, not a & b, a & not b, false);
|
||
|
until not a & not b then C1
|
||
|
| not a & b then C2
|
||
|
| a & not b then C3
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
|
||
|
|
||
|
(* core availability in the paper it's called proc *)
|
||
|
node core_mode(disable:bool)returns(active:bool)
|
||
|
let
|
||
|
automaton
|
||
|
state COREON do
|
||
|
active= true;
|
||
|
until disable then COREOFF
|
||
|
|
||
|
state COREOFF do
|
||
|
active= false;
|
||
|
until not disable then COREON
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
|
||
|
(* computes the communication cost associated with each core hosting the tasks *)
|
||
|
(* in the paper there is additional inputs f: frequency c: function cost *)
|
||
|
|
||
|
node communication_cost(core1, core2:core)returns(costcpu1, costcpu2:int)
|
||
|
var sameproc, samecore:bool;
|
||
|
task1_cpu, task1_core, task2_cpu, task2_core:bool;
|
||
|
let
|
||
|
|
||
|
switch core1
|
||
|
| C1 do (task1_cpu, task1_core)=(false, false)
|
||
|
| C2 do (task1_cpu, task1_core)=(false, true);
|
||
|
| C3 do (task1_cpu, task1_core)=(true, false);
|
||
|
| C4 do (task1_cpu, task1_core)=(true, true);
|
||
|
end ;
|
||
|
|
||
|
switch core2
|
||
|
| C1 do (task2_cpu, task2_core)=(false, false)
|
||
|
| C2 do (task2_cpu, task2_core)=(false, true);
|
||
|
| C3 do (task2_cpu, task2_core)=(true, false);
|
||
|
| C4 do (task2_cpu, task2_core)=(true, true);
|
||
|
end ;
|
||
|
|
||
|
sameproc = (task1_cpu & task2_cpu) or (not task1_cpu & not task2_cpu);
|
||
|
samecore = sameproc & ((task1_core & task2_core) or (not task1_core & not task2_core));
|
||
|
|
||
|
(costcpu1, costcpu2)= if samecore then (10,20)
|
||
|
else if sameproc then (20,40)
|
||
|
else (50,100);
|
||
|
tel
|
||
|
|
||
|
|
||
|
(* associates the cost to the given coreId *)
|
||
|
node core_cost(coreId:core; cost:int)returns(c1, c2, c3, c4:int)
|
||
|
let
|
||
|
switch coreId
|
||
|
| C1 do (c1,c2,c3,c4)= (cost, 0,0,0)
|
||
|
| C2 do (c1,c2,c3,c4)= (0,cost,0,0)
|
||
|
| C3 do (c1,c2,c3,c4)= (0,0,cost,0)
|
||
|
| C4 do (c1,c2,c3,c4)= (0,0,0,cost);
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
(* modeling asynchronous commands *)
|
||
|
node command(start, isdone: bool)returns(pending:bool)
|
||
|
let
|
||
|
automaton
|
||
|
state DONE do
|
||
|
pending = false;
|
||
|
until start then PENDING
|
||
|
|
||
|
state PENDING do
|
||
|
pending=true;
|
||
|
until isdone then DONE
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
|
||
|
(* ======================================== some utility nodes ============================================= *)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
(* retruns an integer representation of the coreId*)
|
||
|
node compute_core(coreId:core; active:bool)returns(icore:int)
|
||
|
let
|
||
|
|
||
|
switch coreId
|
||
|
| C1 do icore = if(active) then 1 else 0
|
||
|
| C2 do icore = if(active) then 2 else 0
|
||
|
| C3 do icore = if(active) then 3 else 0
|
||
|
| C4 do icore = if(active) then 4 else 0
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
|
||
|
(* tells whether a task is running on core 3*)
|
||
|
node comOn3(coreId:core)returns(yes:bool)
|
||
|
let
|
||
|
switch coreId
|
||
|
| C1 do yes = false
|
||
|
| C2 do yes = false
|
||
|
| C3 do yes = true
|
||
|
| C4 do yes = false
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
(* tells whether a task is running on core 1*)
|
||
|
node comOn1(coreId:core)returns(yes:bool)
|
||
|
let
|
||
|
switch coreId
|
||
|
| C1 do yes = true
|
||
|
| C2 do yes = false
|
||
|
| C3 do yes = false
|
||
|
| C4 do yes = false
|
||
|
end;
|
||
|
tel
|
||
|
|
||
|
|
||
|
(* tells whether two cores are equivalent *)
|
||
|
node same_core(core1:core; core2: core) returns(samecore:bool)
|
||
|
var sameproc:bool;
|
||
|
task1_cpu, task1_core, task2_cpu, task2_core:bool;
|
||
|
let
|
||
|
switch core1
|
||
|
| C1 do (task1_cpu, task1_core)=(false, false)
|
||
|
| C2 do (task1_cpu, task1_core)=(false, true);
|
||
|
| C3 do (task1_cpu, task1_core)=(true, false);
|
||
|
| C4 do (task1_cpu, task1_core)=(true, true);
|
||
|
end ;
|
||
|
|
||
|
switch core2
|
||
|
| C1 do (task2_cpu, task2_core)=(false, false)
|
||
|
| C2 do (task2_cpu, task2_core)=(false, true);
|
||
|
| C3 do (task2_cpu, task2_core)=(true, false);
|
||
|
| C4 do (task2_cpu, task2_core)=(true, true);
|
||
|
end ;
|
||
|
|
||
|
sameproc = (task1_cpu & task2_cpu) or (not task1_cpu & not task2_cpu);
|
||
|
samecore = sameproc & ((task1_core & task2_core) or (not task1_core & not task2_core));
|
||
|
tel
|
||
|
|
||
|
|
||
|
(* this implments the boolean equivalence *)
|
||
|
|
||
|
node bool_equi(a,b:bool) returns (res:bool)
|
||
|
let
|
||
|
res = ((a or not b) & (b or not a));
|
||
|
tel
|
||
|
|
||
|
(* this implments the boolean implication *)
|
||
|
|
||
|
node bool_impl(a,b:bool) returns (res:bool)
|
||
|
let
|
||
|
res = (not a or b) ;
|
||
|
tel
|
||
|
|
||
|
|
||
|
|
||
|
(* ==================================================================================*)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
(* main program *)
|
||
|
node main(disable: bool; fifoH1F, fifoH2F, fifoL2F, changeL2:bool; c_startH2_done, c_stopH2_done:bool) returns(
|
||
|
h2Required:bool;
|
||
|
h2NotRequired:bool;
|
||
|
noOneOnC3WhenOff:bool;
|
||
|
costgood:bool;
|
||
|
notF2whenLogger:bool;
|
||
|
startH2:bool; unboundH2:bool;
|
||
|
startL2:bool; unboundL2:bool;
|
||
|
c_startH2, c_stopH2, c_connectH2, c_diconnectH2:bool;
|
||
|
c_startL, c_stopL, c_connectL, c_diconnectL:bool;
|
||
|
a_cmd_pending:bool
|
||
|
)
|
||
|
|
||
|
|
||
|
|
||
|
(* BEGIN CONTRACT *)
|
||
|
(*====================================================*)
|
||
|
contract
|
||
|
|
||
|
let
|
||
|
|
||
|
|
||
|
tel
|
||
|
assume(true)
|
||
|
|
||
|
enforce((a_cmd_pending or h2Required)
|
||
|
& (a_cmd_pending or h2NotRequired)
|
||
|
& noOneOnC3WhenOff
|
||
|
& costgood
|
||
|
& (a_cmd_pending or notF2whenLogger))
|
||
|
with(cDa, cDb:bool;
|
||
|
cSAa, cSAb:bool;
|
||
|
cSBa, cSBb:bool;
|
||
|
changeH2, killH2:bool
|
||
|
)
|
||
|
(*====================================================*)
|
||
|
(* END CONTRACT *)
|
||
|
|
||
|
|
||
|
var
|
||
|
c_startH2_pending, c_stopH2_pending:bool;
|
||
|
c1,c2,c3,c4:int; pf, pa, pd, pf1, pf2, pl:int;
|
||
|
|
||
|
(* these vars are true when no one is running on the associate core *)
|
||
|
noOneOnC3:bool;
|
||
|
|
||
|
(* vars to describe the desired max corecosts
|
||
|
when there is only 3 cores and when there is 4 cores available
|
||
|
*)
|
||
|
|
||
|
costNActive:bool; costActive:bool;
|
||
|
|
||
|
(* component cores *)
|
||
|
frend_core, ana_core, disp_core, file1_core, file2_core, logger_core :core;
|
||
|
|
||
|
|
||
|
(* communication costs for each binding server/client side*)
|
||
|
costAs, costAc:int; (*cost of the communication line between frend and ana*)
|
||
|
costBs, costBc:int; (*cost of the communication line between ana and disp*)
|
||
|
costCs, costCc:int; (*cost of the communication line between ana and logger*)
|
||
|
costDs, costDc:int; (*cost of the communication line between disp and file1*)
|
||
|
costFs, costFc:int; (*cost of the communication line between disp and file2*)
|
||
|
|
||
|
(*core 1,2,3,4 workload*)
|
||
|
cost1, cost2, cost3, cost4: int;
|
||
|
|
||
|
costAs1, costAs2, costAs3, costAs4:int; (*cost of the communication line A on each core -- server side*)
|
||
|
costBs1, costBs2, costBs3, costBs4:int; (*cost of the communication line B on each core -- server side*)
|
||
|
costCs1, costCs2, costCs3, costCs4:int; (*cost of the communication line C on each core -- server side*)
|
||
|
costDs1, costDs2, costDs3, costDs4:int; (*cost of the communication line D on each core -- server side*)
|
||
|
costFs1, costFs2, costFs3, costFs4:int; (*cost of the communication line F on each core -- server side*)
|
||
|
|
||
|
costAc1, costAc2, costAc3, costAc4:int; (*cost of the communication line A on each core -- client side*)
|
||
|
costBc1, costBc2, costBc3, costBc4:int; (*cost of the communication line B on each core -- client side*)
|
||
|
costCc1, costCc2, costCc3, costCc4:int; (*cost of the communication line C on each core -- client side*)
|
||
|
costDc1, costDc2, costDc3, costDc4:int; (*cost of the communication line D on each core -- client side*)
|
||
|
costFc1, costFc2, costFc3, costFc4:int; (*cost of the communication line F on each core -- client side*)
|
||
|
|
||
|
core3:bool; (* state of the core number 3 ON/OFF*)
|
||
|
|
||
|
fifoH1Full, fifoH2Bull, fifoL2Bull : bool; (*satte of the fifos associated with filehandlers and logger*)
|
||
|
|
||
|
(* intermediate variables to control task positions *)
|
||
|
iFa, iFb : bool;
|
||
|
iAa, iAb : bool;
|
||
|
iDa, iDb : bool;
|
||
|
iF1a, iF1b : bool;
|
||
|
iF2a, iF2b : bool;
|
||
|
iLa, iLb : bool;
|
||
|
|
||
|
(* migration commands. those that are not output*)
|
||
|
c_mig1f , c_mig2f , c_mig3f , c_mig4f,
|
||
|
c_mig1a , c_mig2a , c_mig3a , c_mig4a,
|
||
|
c_mig1f1 , c_mig2f1 , c_mig3f1 , c_mig4f1,
|
||
|
c_mig1l , c_mig2l , c_mig3l , c_mig4l,
|
||
|
c_mig1f2 , c_mig2f2 , c_mig3f2 , c_mig4f2 ,
|
||
|
c_mig1d , c_mig2d , c_mig3d , c_mig4d:bool;
|
||
|
|
||
|
|
||
|
(* two boolean variables to set the enforced propertie true for the 3 first instants *)
|
||
|
count0, count1 : bool ;
|
||
|
|
||
|
let
|
||
|
|
||
|
|
||
|
(* controlling task positions *)
|
||
|
(iFa, iFb)=(false->true, false->true); (* frontend always on Core 2*)
|
||
|
(iAa, iAb)=(false->true, false->true); (* analyzer manager always on Core2*)
|
||
|
(iDa, iDb)=(true->cDa, false->cDb); (* dispa core 4 at the begining*)
|
||
|
(iF1a, iF1b)=(true->cSAa, false->cSAb); (* fileh1 on core 4 at first *)
|
||
|
(iF2a, iF2b)=(true->cSBa, false->cSBb); (* file2 core 4 at first *)
|
||
|
(iLa, iLb)=(true->true, false->true); (* logger always on Core 4*)
|
||
|
|
||
|
|
||
|
(* Computnig the cost of each core *)
|
||
|
cost1= costAs1+ costBs1 + costCs1 + costDs1 + costFs1
|
||
|
+ costAc1 + costBc1 + costCc1 + costDc1 + costFc1;
|
||
|
|
||
|
cost2= costAs2+ costBs2 + costCs2 + costDs2 + costFs2
|
||
|
+ costAc2 + costBc2 + costCc2 + costDc2 + costFc2;
|
||
|
|
||
|
cost3= costAs3+ costBs3 + costCs3 + costDs3 + costFs3 +
|
||
|
costAc3 + costBc3 + costCc3 + costDc3 + costFc3;
|
||
|
|
||
|
cost4= costAs4+ costBs4 + costCs4 + costDs4 + costFs4 +
|
||
|
costAc4 + costBc4 + costCc4 + costDc4 + costFc4;
|
||
|
|
||
|
|
||
|
|
||
|
(* filehandler2 lifecycyle and the workload it induces *)
|
||
|
(startH2, unboundH2, c_startH2, c_connectH2, c_stopH2, c_diconnectH2)= inlined lifecycle(not changeH2, not killH2 , not fifoH2Bull);
|
||
|
(costFc, costFs) = if (not startH2) then (0,0) else inlined communication_cost(disp_core,file2_core);
|
||
|
|
||
|
|
||
|
(* Logger lifeCycle and the workload it induces *)
|
||
|
(startL2, unboundL2, c_startL, c_connectL, c_stopL, c_diconnectL)= inlined lifecycle(changeL2, false, not fifoL2Bull);
|
||
|
(costCc, costCs) = if (not startL2) then (0,0) else inlined communication_cost(ana_core,logger_core);
|
||
|
|
||
|
|
||
|
(*switch on/off core 3*)
|
||
|
core3= inlined core_mode(disable);
|
||
|
|
||
|
|
||
|
(* the fifio associated with file1 component input*)
|
||
|
fifoH1Full = inlined fifo(fifoH1F);
|
||
|
|
||
|
(* the fifio associated with file2 component input*)
|
||
|
fifoH2Bull = inlined fifo(fifoH2F);
|
||
|
|
||
|
(* the fifio associated with logger component input*)
|
||
|
fifoL2Bull = inlined fifo(fifoL2F);
|
||
|
|
||
|
|
||
|
(* component mapping *)
|
||
|
(frend_core, c_mig1f , c_mig2f , c_mig3f , c_mig4f)= inlined position(iFa, iFb);
|
||
|
(ana_core, c_mig1a , c_mig2a , c_mig3a , c_mig4a)= inlined position(iAa, iAb);
|
||
|
(file1_core, c_mig1f1 , c_mig2f1 , c_mig3f1 , c_mig4f1)= inlined position(iF1a, iF1b);
|
||
|
(disp_core, c_mig1d , c_mig2d , c_mig3d , c_mig4d)= inlined position(iDa, iDb);
|
||
|
(file2_core, c_mig1f2 , c_mig2f2 , c_mig3f2 , c_mig4f2)= inlined position(iF2a, iF2b);
|
||
|
(logger_core, c_mig1l , c_mig2l , c_mig3l , c_mig4l)= inlined position(iLa, iLb);
|
||
|
|
||
|
(* communication lines cost server/client side *)
|
||
|
(costAc, costAs) = inlined communication_cost(frend_core, ana_core);
|
||
|
(costBc, costBs) = inlined communication_cost(ana_core, disp_core);
|
||
|
(costDc, costDs) = inlined communication_cost(disp_core, file1_core);
|
||
|
|
||
|
|
||
|
|
||
|
(* associating each communiaction line cost to the concerned processor *)
|
||
|
(costAs1, costAs2, costAs3, costAs4) = inlined core_cost(ana_core, costAs);
|
||
|
(costAc1, costAc2, costAc3, costAc4) = inlined core_cost(frend_core, costAc);
|
||
|
|
||
|
(costBs1, costBs2, costBs3, costBs4) = inlined core_cost(disp_core, costBs);
|
||
|
(costBc1, costBc2, costBc3, costBc4) = inlined core_cost(ana_core, costBc);
|
||
|
|
||
|
(costCs1, costCs2, costCs3, costCs4) = inlined core_cost(logger_core, costCs);
|
||
|
(costCc1, costCc2, costCc3, costCc4) = inlined core_cost(ana_core, costCc);
|
||
|
|
||
|
(costDs1, costDs2, costDs3, costDs4) = inlined core_cost(file1_core, costDs);
|
||
|
(costDc1, costDc2, costDc3, costDc4) = inlined core_cost(disp_core, costDc);
|
||
|
|
||
|
(costFs1, costFs2, costFs3, costFs4) = inlined core_cost(file2_core, costFs);
|
||
|
(costFc1, costFc2, costFc3, costFc4) = inlined core_cost(disp_core, costFc);
|
||
|
|
||
|
(* outputs/properties *)
|
||
|
|
||
|
(* core costs *)
|
||
|
(c1, c2, c3, c4)= (cost1, cost2, cost3, cost4);
|
||
|
|
||
|
(* component positions -- from enumerated type to integers *)
|
||
|
pf = inlined compute_core(frend_core, true);
|
||
|
pa = inlined compute_core(ana_core, true);
|
||
|
pf1 = inlined compute_core(file1_core, true);
|
||
|
pf2 = inlined compute_core(file2_core, startH2);
|
||
|
pl = inlined compute_core(logger_core, startL2);
|
||
|
pd = inlined compute_core(disp_core, true);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
noOneOnC3 = not (inlined comOn3(file1_core)
|
||
|
or inlined comOn3(file2_core)
|
||
|
or inlined comOn3(disp_core)
|
||
|
or inlined comOn3(logger_core)
|
||
|
or inlined comOn3(frend_core)
|
||
|
or inlined comOn3(ana_core)
|
||
|
);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
count0 = false -> true;
|
||
|
count1 = false fby count0;
|
||
|
|
||
|
|
||
|
(* Asychronous commands *)
|
||
|
c_startH2_pending= inlined command(c_startH2, c_startH2_done);
|
||
|
c_stopH2_pending= inlined command(c_stopH2, c_stopH2_done);
|
||
|
a_cmd_pending = c_startH2_pending or c_stopH2_pending;
|
||
|
|
||
|
(* properties to enforce *)
|
||
|
|
||
|
(* when logger is on, the file2 cannot be started *)
|
||
|
notF2whenLogger = inlined bool_impl(startL2 & not unboundL2, unboundH2);
|
||
|
|
||
|
(*When core 3 is off, no one can run on it *) (*may be done without ifthenelse*)
|
||
|
noOneOnC3WhenOff = if(core3) then true else noOneOnC3;
|
||
|
|
||
|
|
||
|
(* FileHandler 2 is required when the fifo of file1 is full *)
|
||
|
h2Required = inlined bool_impl(not startL2 & fifoH1Full, startH2 & not unboundH2);
|
||
|
|
||
|
(* FileHandler 2 is not required when the fifo of file1 is Empty *)
|
||
|
(* We just disconnect it, it will be stopped once its fifo is empty*)
|
||
|
h2NotRequired = inlined bool_impl(not fifoH1Full,unboundH2);
|
||
|
|
||
|
(* workload when 3 cores or 4 cores *)
|
||
|
costActive=(c1<=170 & (c2<=180) & c3<=180 & c4<=140);
|
||
|
costNActive=(c1<=280 & c2<=280 & c3<=280 & c4<=280);
|
||
|
costgood = if(not count1)then true else (if core3 then costActive else costNActive);
|
||
|
tel
|