| """ |
| | Copyright (C) 2011-2017 Philip Axer |
| | TU Braunschweig, Germany |
| | All rights reserved. |
| | See LICENSE file for copyright and license details. |
| |
| :Authors: |
| - Philip Axer |
| |
| Description |
| ----------- |
| |
| Symta 1.4 loader |
| """ |
| |
| from __future__ import absolute_import |
| |
| import xml.dom.minidom |
| |
| from . import model |
| from . import schedulers |
| |
| import logging |
| |
| logger = logging.getLogger("symta_loader") |
| |
| class InvalidSymtaXMLException (Exception): |
| def __init__(self, value, dom_node): |
| self.value = value |
| self.dom_node = dom_node |
| def __str__(self): |
| return repr(self.value + " in node " % self.dom_node.nodeName) |
| |
| class SymtaLoader14(object): |
| """ a simple SymTA/S xml loader |
| reverse engineered sources, implements only a functional subset |
| """ |
| def __init__(self): |
| self.system = model.System() |
| |
| # # tasks in the system |
| self.tasks = set() |
| |
| # # name -> task map |
| self.task_map = dict() |
| |
| # # resources in the system |
| self.resources = set() |
| |
| # # name -> resource map |
| self.resources_map = dict() |
| |
| # # we will just store the EventModel as a source |
| self.sources = set() |
| |
| # # name -> sources map |
| self.sources_map = dict() |
| |
| def parse(self, filename): |
| self.system.dom_node = xml.dom.minidom.parse(filename) |
| self._handle_symta_system(self.system.dom_node) |
| return self.system |
| |
| def _handle_symta_system(self, symtasystem_node): |
| |
| application_node = symtasystem_node.getElementsByTagName("application")[0] |
| self._handle_application(application_node) |
| |
| architecture_node = symtasystem_node.getElementsByTagName("architecture")[0] |
| self._handle_architecture(architecture_node) |
| |
| mapping_node = symtasystem_node.getElementsByTagName("mapping")[0] |
| self._handle_mapping(mapping_node) |
| |
| observedpaths_node = symtasystem_node.getElementsByTagName("observedpaths")[0] |
| |
| def _handle_mapping(self, mapping_node): |
| mappings = mapping_node.getElementsByTagName("map:task") |
| for map in mappings: |
| task_name = map.attributes['name'].nodeValue |
| task = self.task_map[task_name] |
| |
| actual_mapping_node = map.getElementsByTagName("actualMapping")[0] |
| schedparam_node = actual_mapping_node.getElementsByTagName("schedparam")[0] |
| |
| task.scheduling_parameter = int(schedparam_node.attributes['priority'].nodeValue) |
| |
| resource_name = actual_mapping_node.attributes['name'].nodeValue |
| |
| resource = self.resources_map[resource_name] |
| |
| assert resource in self.system.resources |
| |
| resource.bind_task(task) |
| |
| assert task in resource.tasks |
| task.bcet *= resource.speedup |
| task.wcet *= resource.speedup |
| |
| logger.info("task %s, sched_param %d is mapped to %s", task.name, task.scheduling_parameter, resource_name) |
| |
| def _handle_architecture(self, architecture_node): |
| cpu_nodes = architecture_node.getElementsByTagName("cpu") |
| for cpu_node in cpu_nodes: |
| resource = self._handle_cpu(cpu_node) |
| |
| def _get_scheduler_function(self, scheduler_string): |
| if scheduler_string == "(IDA)spp" or scheduler_string == "spp": |
| return schedulers.SPPScheduler() |
| elif scheduler_string == "(IDA)roundrobin" or scheduler_string == "roundrobin": |
| return schedulers.RoundRobinScheduler() |
| elif scheduler_string == "(IDA)spnp" or scheduler_string == "spnp": |
| return schedulers.SPNPScheduler() |
| else: |
| raise InvalidSymtaXMLException("Scheduler %s is not compatible with pycpa" % scheduler_string) |
| |
| def _handle_cpu(self, cpu_node): |
| resource_name = cpu_node.attributes['name'].nodeValue |
| scheduler_string = cpu_node.attributes['scheduler'].nodeValue |
| scheduler = self._get_scheduler_function(scheduler_string) |
| |
| resource = self.system.bind_resource(model.Resource(resource_name, scheduler)) |
| |
| speedup_node = cpu_node.getElementsByTagName("speedup")[0] |
| speedup = self._handle_speedup(speedup_node) |
| resource.speedup = speedup |
| |
| self.resources.add(resource) |
| self.resources_map[resource.name] = resource |
| |
| |
| logger.info("new resource %s, speedup %f" % (str(resource.name), speedup)) |
| return resource |
| |
| def _handle_application(self, application_node): |
| tasks = application_node.getElementsByTagName("task") |
| for taskNode in tasks: |
| self._handle_task(taskNode) |
| |
| sources = application_node.getElementsByTagName("source") |
| for sourceNode in sources: |
| self._handle_source(sourceNode) |
| |
| eventstream_nodes = application_node.getElementsByTagName("eventstream") |
| for eventstream_node in eventstream_nodes: |
| self._handle_eventstream(eventstream_node) |
| |
| def _handle_eventstream(self, eventstream_node): |
| name = eventstream_node.attributes['name'].nodeValue |
| |
| src_node = eventstream_node.getElementsByTagName('src')[0]; |
| src_name = src_node.attributes['process'].nodeValue |
| src_type_name = src_node.attributes['type'].nodeValue |
| |
| target_node = eventstream_node.getElementsByTagName('target')[0] |
| target_name = target_node.attributes['process'].nodeValue |
| target_type_name = target_node.attributes['type'].nodeValue |
| |
| target = None |
| if target_type_name == "task": |
| target = self.task_map[target_name] |
| elif target_type_name == "sink": |
| logging.info("skipping event stream %s with sink target %s" % (name, target_name)) |
| |
| if src_type_name == "source": |
| assert target is not None |
| src_em = self.sources_map[src_name] |
| target.in_event_model = src_em |
| logging.info("%s: assinged event model %s to task %s" % (name, str(src_em), target.name)) |
| elif src_type_name == "task": |
| src = self.task_map[src_name] |
| if target is not None: |
| src.link_dependent_task(target) |
| logging.info("%s: linked %s -> %s" % (name, src.name, target.name)) |
| |
| def _handle_task(self, task_node): |
| assert task_node.nodeName == "task" |
| name = task_node.attributes["name"].nodeValue |
| ports = task_node.getElementsByTagName("ports")[0] # take first |
| speedup = self._handle_speedup(task_node.getElementsByTagName("speedup")[0]) # take first |
| bcet, wcet = self._handle_tcore(task_node.getElementsByTagName("tCore")[0]) # take first |
| bcet *= speedup |
| wcet *= speedup |
| # inport_list, outport_list = self._handle_ports(ports) |
| logger.info("new task %s, tcore: [%f, %f] speedfactor %f" % (name, bcet, wcet, speedup)) |
| task = model.Task(name=name, bcet=bcet, wcet=wcet, sched_param=None) |
| task.dom_node = task_node |
| task.ports = ports # used later to connect the event streams |
| self.tasks.add(task) |
| self.task_map[name] = task |
| |
| def _handle_tcore(self, tCoreNode): |
| return self._handle_time_interval(tCoreNode.getElementsByTagName("timeinterval")[0]) |
| |
| def _handle_time_interval(self, timeIntervalNode): |
| assert timeIntervalNode.nodeName == "timeinterval" |
| timevalues = timeIntervalNode.getElementsByTagName("timevalue") |
| lower = self._handle_time_value(timevalues[0]) |
| upper = self._handle_time_value(timevalues[1]) |
| return (lower, upper) |
| |
| def _handle_time_value(self, timeNode): |
| # loss of precison due to hard coded devision |
| # TODO: switch to integers |
| assert timeNode.nodeName == "timevalue" |
| numerator = float(timeNode.attributes["numerator"].nodeValue) |
| denominator = float(timeNode.attributes["denominator"].nodeValue) |
| return numerator / denominator |
| |
| def _handle_source(self, sourceNode): |
| assert sourceNode.nodeName == "source" |
| name = sourceNode.attributes['name'].nodeValue |
| ports = sourceNode.getElementsByTagName("ports")[0] |
| inport_list, outport_list = self._handle_ports(ports) |
| port_name, em = outport_list[0] |
| em.name = name |
| self.sources.add(em) |
| self.sources_map[name] = em |
| # graph_extension_container = sourceNode.getElementsByTagName("GraphElementExtensionContainer")[0] |
| |
| logger.info("new source %s %s" % (name, str(em))) |
| |
| def _handle_ports(self, portsNode): |
| inport_list = list() |
| outport_list = list() |
| # we assume there is only one port |
| outports = portsNode.getElementsByTagName("outputport") |
| for outportNode in outports: |
| propagation_container = outportNode.getElementsByTagName("PropagationContainer")[0] |
| event_model = self._handle_propagation_container(propagation_container) |
| name = outportNode.attributes["name"].nodeValue |
| outport_list.append((name, event_model)) |
| |
| inports = portsNode.getElementsByTagName("inputport") |
| for inportNode in inports: |
| name = inportNode.attributes["name"].nodeValue |
| event_model = self._handle_propagation_container(inportNode.getElementsByTagName("PropagationContainer")[0]) |
| inport_list.append((name, event_model)) |
| return inport_list, outport_list |
| |
| def _handle_propagation_container(self, propagationContainerNode): |
| |
| # just grab the event model |
| # print propagationContainerNode.nodeName |
| # print propagationContainerNode.nodeValue |
| propagationElement = propagationContainerNode.getElementsByTagName("PropagationElements")[0] |
| event_model_propagation_element = propagationElement.getElementsByTagName("EventModelPropagationElement")[0] |
| myEventModel = event_model_propagation_element.getElementsByTagName("myEventModel")[0] |
| standardeventmodel = myEventModel.getElementsByTagName("standardeventmodel")[0] |
| return self._handle_standardeventmodel(standardeventmodel) |
| |
| def _handle_standardeventmodel(self, standardeventmodel_node): |
| assert standardeventmodel_node.nodeName == "standardeventmodel" |
| eventmodeltype = standardeventmodel_node.getElementsByTagName("eventmodeltype")[0] |
| |
| period_node = standardeventmodel_node.getElementsByTagName("period")[0] |
| period = self._handle_time_value(period_node.childNodes[1]) |
| |
| jitter_node = standardeventmodel_node.getElementsByTagName("jitter")[0] |
| jitter = self._handle_time_value(jitter_node.childNodes[1]) |
| |
| mindist_node = standardeventmodel_node.getElementsByTagName("minDist")[0] |
| mindist = self._handle_time_value(mindist_node.childNodes[1]) |
| |
| em = model.PJdEventModel() |
| em.set_PJd(period, jitter, mindist) |
| em.dom_node = standardeventmodel_node |
| |
| return em |
| |
| def _handle_speedup(self, speedup): |
| factor = speedup.attributes['factor'] |
| return float(factor.nodeValue) |
| |
| class SymtaWriter(object): |
| """ not implemented """ |
| pass |
| # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 |