Pipeline¶
Pipelines allow to arbitrarly interconnect generators and resources by chaining them. Messages belonging to a pipeline automatically flow from a resource to another without the needs of explicitly defining the hops. Please note that a generator (and their messages) belong only to a single pipeline. If multiple pipelines are needed simultaneously, they need to be merged fisrt. See Branching pipeline for more details.
Single pipeline¶
Let’s start with a simulation where messages are generated by Generator #0
and are served by Resource #0
and Resource #1
.
|Generator #0| -> |Resource #0| -> |Resource #1|
The SimPype code would hence be:
import simpype
import random
sim = simpype.Simulation(id = 'single')
gen0 = sim.add_generator(id = 'gen0')
gen0.random['arrival'] = {0: lambda: random.expovariate(1.0)}
res0 = sim.add_resource(id = 'res0')
res0.random['service'] = {0: lambda: random.expovariate(2.0)}
res1 = sim.add_resource(id = 'res1')
res1.random['service'] = {0: lambda: random.expovariate(2.0)}
p0 = sim.add_pipeline(gen0, res0, res1)
sim.run(until = 5)
As it can be noticed in sim.log
file, messages generated by Generator #0
automatically flow through Resource #0
and Resource #1
without the needs of explicitly defining the next hop:
timestamp,message,seq_num,resource,event
0.000000000,gen0,0,res0,pipe.in
0.000000000,gen0,0,res0,pipe.out
0.044474460,gen0,0,res0,resource.serve
0.044474460,gen0,0,res1,pipe.in
0.044474460,gen0,0,res1,pipe.out
0.867233916,gen0,1,res0,pipe.in
0.867233916,gen0,1,res0,pipe.out
1.099185483,gen0,0,res1,resource.serve
1.876512438,gen0,1,res0,resource.serve
1.876512438,gen0,1,res1,pipe.in
1.876512438,gen0,1,res1,pipe.out
2.873364054,gen0,1,res1,resource.serve
Overlapping pipelines¶
Noe let’s continue with a simulation scenarios like the following:
|Generator #0| -\ /-> |Resource #1|
)-> |Resource #0| -(
|Generator #1| -/ \-> |Resource #2|
In this scenario we want to reproduce the following interconnection:
|Generator #0| -> |Resource #0| -> |Resource #1|
|Generator #1| -> |Resource #0| -> |Resource #2|
As it can be noticed, there are two dinstinct paths/pipelines that overlap at Resource #0
.
However, any messages generated by Generator #0
should end to Resource #1
.
Similarly, any messages generated by Generator #1
should end to Resource #2
.
In this scenario, Resource #0
is hence shared between the two pipelines.
The SimPype code would hence be:
import simpype
import random
sim = simpype.Simulation(id = 'overlap')
gen0 = sim.add_generator(id = 'gen0')
gen0.random['arrival'] = {0: lambda: random.expovariate(1.0)}
gen1 = sim.add_generator(id = 'gen1')
gen1.random['arrival'] = {0: lambda: random.expovariate(1.0)}
res0 = sim.add_resource(id = 'res0')
res0.random['service'] = {0: lambda: random.expovariate(4.0)}
res1 = sim.add_resource(id = 'res1')
res1.random['service'] = {0: lambda: random.expovariate(2.0)}
res2 = sim.add_resource(id = 'res2')
res2.random['service'] = {0: lambda: random.expovariate(2.0)}
p0 = sim.add_pipeline(gen0, res0, res1)
p1 = sim.add_pipeline(gen1, res0, res2)
sim.run(until = 2.5)
As it can be noticed in sim.log
file, messages generated by Generator #0
automatically flow through Resource #0
and Resource #1
and messages generated by Generator #1
automatically flow through Resource #0
and Resource #2
. Moreover, Resource #0
is shared between the two pipelines:
timestamp,message,seq_num,resource,event
0.000000000,gen0,0,res0,pipe.in
0.000000000,gen1,0,res0,pipe.in
0.000000000,gen0,0,res0,pipe.out
0.372608250,gen0,0,res0,resource.serve
0.372608250,gen0,0,res1,pipe.in
0.372608250,gen0,0,res1,pipe.out
0.372608250,gen1,0,res0,pipe.out
0.515112655,gen0,1,res0,pipe.in
0.636849329,gen1,0,res0,resource.serve
0.636849329,gen1,0,res2,pipe.in
0.636849329,gen1,0,res2,pipe.out
0.636849329,gen0,1,res0,pipe.out
0.653319564,gen0,1,res0,resource.serve
0.653319564,gen0,1,res1,pipe.in
0.684766776,gen1,1,res0,pipe.in
0.684766776,gen1,1,res0,pipe.out
0.851617505,gen0,0,res1,resource.serve
0.851617505,gen0,1,res1,pipe.out
0.921614468,gen1,2,res0,pipe.in
0.949578262,gen1,1,res0,resource.serve
0.949578262,gen1,1,res2,pipe.in
0.949578262,gen1,2,res0,pipe.out
1.052881475,gen1,2,res0,resource.serve
1.052881475,gen1,2,res2,pipe.in
1.079748898,gen0,1,res1,resource.serve
1.245866822,gen1,3,res0,pipe.in
1.245866822,gen1,3,res0,pipe.out
1.352498249,gen1,0,res2,resource.serve
1.352498249,gen1,1,res2,pipe.out
1.369990105,gen1,4,res0,pipe.in
1.384336838,gen1,1,res2,resource.serve
1.384336838,gen1,2,res2,pipe.out
1.385217621,gen1,5,res0,pipe.in
1.418331444,gen1,2,res2,resource.serve
1.582122574,gen1,3,res0,resource.serve
1.582122574,gen1,3,res2,pipe.in
1.582122574,gen1,3,res2,pipe.out
1.582122574,gen1,4,res0,pipe.out
2.028251841,gen1,4,res0,resource.serve
2.028251841,gen1,4,res2,pipe.in
2.028251841,gen1,5,res0,pipe.out
2.148959938,gen1,6,res0,pipe.in
Branching pipeline¶
Now let’s continue with a pipeline having a branching point with one generator and three resources:
/-> |Resource #1|
|Generator #0| -> |Resource #0| -(
\-> |Resource #2|
There are two possible options at this stage:
- Serve a copy of the same message to both
Resource #1
andResource #2
;- Either serve a message to
Resource #1
or toResource #2
.
Automatic copy¶
In case of serving a copy of the same message to both Resource #1
and Resource #2
, the SimPype code would hence be:
import simpype
import random
sim = simpype.Simulation(id = 'single')
gen0 = sim.add_generator(id = 'gen0')
gen0.random['arrival'] = {0: lambda: random.expovariate(1.0)}
res0 = sim.add_resource(id = 'res0')
res0.random['service'] = {0: lambda: random.expovariate(2.0)}
res1 = sim.add_resource(id = 'res1')
res1.random['service'] = {0: lambda: random.expovariate(2.0)}
res2 = sim.add_resource(id = 'res2')
res2.random['service'] = {0: lambda: random.expovariate(2.0)}
p0 = sim.add_pipeline(gen0, res0, res1)
p1 = sim.add_pipeline(gen0, res0, res2)
pM = sim.merge_pipeline(p0, p1)
sim.run(until = 5)
Please note the use of merge_pipeline()
. This function merges multiple pipelines into a single one, thus creating the branching point.
Withouth calling the merge_pipeline()
function, the only active pipeline would have been p1
.
As it can be noticed in sim.log
file, messages are automatically copied and served to both Resource #1
and Resource #2
after being served by Resource #0
:
timestamp,message,seq_num,resource,event
0.000000000,gen0,0,res0,pipe.in
0.000000000,gen0,0,res0,pipe.out
0.412762064,gen0,0,res0,resource.serve
0.412762064,gen0,0,res2,pipe.in
0.412762064,gen0,0,res1,pipe.in
0.412762064,gen0,0,res2,pipe.out
0.412762064,gen0,0,res1,pipe.out
0.631472230,gen0,0,res1,resource.serve
0.989221320,gen0,0,res2,resource.serve
2.545794865,gen0,1,res0,pipe.in
2.545794865,gen0,1,res0,pipe.out
2.572402316,gen0,1,res0,resource.serve
2.572402316,gen0,1,res2,pipe.in
2.572402316,gen0,1,res1,pipe.in
2.572402316,gen0,1,res2,pipe.out
2.572402316,gen0,1,res1,pipe.out
2.602942195,gen0,1,res1,resource.serve
4.163453623,gen0,2,res0,pipe.in
4.163453623,gen0,2,res0,pipe.out
4.222865258,gen0,2,res0,resource.serve
4.222865258,gen0,2,res2,pipe.in
4.222865258,gen0,2,res1,pipe.in
4.222865258,gen0,2,res1,pipe.out
4.270038314,gen0,1,res2,resource.serve
4.270038314,gen0,2,res2,pipe.out
4.360461106,gen0,2,res2,resource.serve
4.551208266,gen0,2,res1,resource.serve
Miscellaneous¶
add_pipeline()
admits both Resource
and Pipeline
objects as arguments as shown in this examples:
import simpype
sim = simpype.Simulation(id = 'single')
gen0 = sim.add_generator(id = 'gen0')
gen1 = sim.add_generator(id = 'gen1')
res0 = sim.add_resource(id = 'res0')
res1 = sim.add_resource(id = 'res1')
res2 = sim.add_resource(id = 'res2')
res3 = sim.add_resource(id = 'res3')
res4 = sim.add_resource(id = 'res4')
res5 = sim.add_resource(id = 'res5')
res6 = sim.add_resource(id = 'res6')
# Only resources
p0 = sim.add_pipeline(res0, res1, res2)
p1 = sim.add_pipeline(res3, res4, res5)
# Mixed pipeline and resources
p2 = sim.add_pipeline(gen0, p0)
p3 = sim.add_pipeline(gen1, p1)
p4 = sim.add_pipeline(p3, res6)
# Only pipelines
# Equivalent to sim.add_pipeline(res0, res1, res2, res3, res4, res5)
p4 = sim.add_pipeline(p0, p1)
Instead, merge_pipeline()
only admits Pipeline
objects as arguments.