from
collections
import
deque
from
SimPy.Simulation
import
Process, Monitor, hold, passivate
from
simso.core.Job
import
Job
from
simso.core.Timer
import
Timer
from
simso.core.CSDP
import
CSDP
import
os
import
os.path
class
TaskInfo(
object
):
def
__init__(
self
, name, identifier, task_type, abort_on_miss, period,
activation_date, n_instr, mix, stack_file, wcet, acet,
et_stddev, deadline, base_cpi, followed_by,
list_activation_dates, preemption_cost, data, my_parameter):
self
.name
=
name
self
.identifier
=
identifier
self
.task_type
=
task_type
self
.period
=
period
self
.activation_date
=
activation_date
self
.n_instr
=
n_instr
self
.mix
=
mix
self
.wcet
=
wcet
self
.acet
=
acet
self
.et_stddev
=
et_stddev
self
.base_cpi
=
base_cpi
self
._stack
=
None
self
._csdp
=
None
self
._stack_file
=
''
self
.set_stack_file(
*
stack_file)
self
.deadline
=
deadline
self
.followed_by
=
followed_by
self
.abort_on_miss
=
abort_on_miss
self
.list_activation_dates
=
list_activation_dates
self
.data
=
data
self
.preemption_cost
=
preemption_cost
self
.my_parameter
=
my_parameter
@property
def
csdp(
self
):
return
self
._csdp
@property
def
stack_file(
self
):
return
self
._stack_file
def
set_stack_file(
self
, stack_file, cur_dir):
if
stack_file:
try
:
self
._stack
=
TaskInfo._parse_stack(stack_file)
self
._csdp
=
CSDP(
self
._stack)
self
._stack_file
=
os.path.relpath(stack_file, cur_dir)
except
Exception as e:
print
(
"set_stack_file failed:"
, e)
@staticmethod
def
_parse_stack(stack_file):
stack
=
{}
if
stack_file
and
os.path.isfile(stack_file):
for
line
in
open
(stack_file):
dist, value
=
line.split()
stack[
int
(dist)]
=
float
(value)
else
:
stack
=
None
return
stack
class
GenericTask(Process):
fields
=
[]
def
__init__(
self
, sim, task_info):
Process.__init__(
self
, name
=
task_info.name, sim
=
sim)
self
.name
=
task_info.name
self
._task_info
=
task_info
self
._monitor
=
Monitor(name
=
"Monitor"
+
self
.name
+
"_states"
,
sim
=
sim)
self
._activations_fifo
=
deque([])
self
._sim
=
sim
self
.cpu
=
None
self
._etm
=
sim.etm
self
._job_count
=
0
self
._last_cpu
=
None
self
._cpi_alone
=
{}
self
._jobs
=
[]
self
.job
=
None
def
__lt__(
self
, other):
return
self
.identifier < other.identifier
def
is_active(
self
):
return
self
.job
is
not
None
and
self
.job.is_active()
def
set_cpi_alone(
self
, proc, cpi):
self
._cpi_alone[proc]
=
cpi
def
get_cpi_alone(
self
, proc
=
None
):
if
proc
is
None
:
proc
=
self
.cpu
return
self
._cpi_alone[proc]
@property
def
base_cpi(
self
):
return
self
._task_info.base_cpi
@property
def
data(
self
):
return
self
._task_info.data
@property
def
deadline(
self
):
return
self
._task_info.deadline
@deadline
.setter
def
deadline(
self
, value):
self
._task_info.deadline
=
value
@property
def
n_instr(
self
):
return
self
._task_info.n_instr
@property
def
mix(
self
):
return
self
._task_info.mix
@property
def
csdp(
self
):
return
self
._task_info.csdp
@property
def
preemption_cost(
self
):
return
self
._task_info.preemption_cost
@property
def
footprint(
self
):
return
int
(
self
._task_info.n_instr
*
self
._task_info.mix
*
(
1
-
self
._task_info.csdp.get(
-
1
)))
@property
def
wcet(
self
):
return
self
._task_info.wcet
@wcet
.setter
def
set_wcet(
self
, value):
'setting'
self
._task_info.wcet
=
value
@property
def
acet(
self
):
return
self
._task_info.acet
@property
def
my_parameter(
self
):
return
self
._task_info.my_parameter
@property
def
et_stddev(
self
):
return
self
._task_info.et_stddev
@property
def
period(
self
):
return
self
._task_info.period
@period
.setter
def
period(
self
,value):
'setting'
self
._task_info.period
=
value
@property
def
identifier(
self
):
return
self
._task_info.identifier
@property
def
monitor(
self
):
return
self
._monitor
@property
def
followed_by(
self
):
if
self
._task_info.followed_by
is
not
None
:
followed
=
[x
for
x
in
self
._sim.task_list
if
(x.identifier
=
=
self
._task_info.followed_by)]
if
followed:
return
followed[
0
]
return
None
@property
def
jobs(
self
):
return
self
._jobs
def
end_job(
self
, job):
self
._last_cpu
=
self
.cpu
if
self
.followed_by:
self
.followed_by.create_job(job)
if
len
(
self
._activations_fifo) >
0
:
self
._activations_fifo.popleft()
if
len
(
self
._activations_fifo) >
0
:
self
.job
=
self
._activations_fifo[
0
]
self
.sim.activate(
self
.job,
self
.job.activate_job())
def
_job_killer(
self
, job):
if
job.end_date
is
None
and
job.computation_time < job.wcet:
if
self
._task_info.abort_on_miss:
self
.cancel(job)
job.abort()
def
create_job(
self
, pred
=
None
):
self
._job_count
+
=
1
job
=
Job(
self
,
"{}_{}"
.
format
(
self
.name,
self
._job_count), pred,
monitor
=
self
._monitor, etm
=
self
._etm, sim
=
self
.sim)
if
len
(
self
._activations_fifo)
=
=
0
:
self
.job
=
job
self
.sim.activate(job, job.activate_job())
self
._activations_fifo.append(job)
self
._jobs.append(job)
timer_deadline
=
Timer(
self
.sim, GenericTask._job_killer,
(
self
, job),
self
.deadline)
timer_deadline.start()
def
_init(
self
):
if
self
.cpu
is
None
:
self
.cpu
=
self
._sim.processors[
0
]
class
ATask(GenericTask):
fields
=
[
'deadline'
,
'wcet'
,
'my_parameter'
]
def
execute(
self
):
self
._init()
yield
passivate,
self
class
PTask(GenericTask):
fields
=
[
'activation_date'
,
'period'
,
'deadline'
,
'wcet'
,
'my_parameter'
]
def
execute(
self
):
self
._init()
yield
hold,
self
,
int
(
self
._task_info.activation_date
*
self
._sim.cycles_per_ms)
while
True
:
self
.create_job()
yield
hold,
self
,
int
(
self
.period
*
self
._sim.cycles_per_ms)
class
SporadicTask(GenericTask):
fields
=
[
'list_activation_dates'
,
'deadline'
,
'wcet'
,
'my_parameter'
]
def
execute(
self
):
self
._init()
for
ndate
in
self
.list_activation_dates:
yield
hold,
self
,
int
(ndate
*
self
._sim.cycles_per_ms) \
-
self
._sim.now()
self
.create_job()
@property
def
list_activation_dates(
self
):
return
self
._task_info.list_activation_dates
task_types
=
{
"Periodic"
: PTask,
"APeriodic"
: ATask,
"Sporadic"
: SporadicTask
}
task_types_names
=
[
"Periodic"
,
"APeriodic"
,
"Sporadic"
]
def
Task(sim, task_info):
return
task_types[task_info.task_type](sim, task_info)