Class: Syskit::NetworkGeneration::SystemNetworkGenerator
- Extended by:
- Logger::Hierarchy
- Includes:
- Logger::Hierarchy, Roby::DRoby::EventLogging
- Defined in:
- lib/syskit/network_generation/system_network_generator.rb
Overview
Generate a plan from a set of InstanceRequirement objects
It generates the canonical, non-deployed, plan. It does not take care of the adaptation of an existing plan into the generated one
Instance Attribute Summary collapse
-
#event_logger ⇒ Object
readonly
Returns the value of attribute event_logger.
-
#merge_solver ⇒ Object
readonly
Returns the value of attribute merge_solver.
-
#plan ⇒ Object
readonly
Returns the value of attribute plan.
Class Method Summary collapse
- .remove_abstract_composition_optional_children(plan) ⇒ Object
-
.verify_device_allocation(plan) ⇒ Object
Verifies that all tasks that are device drivers have at least one device attached, and that the same device is not attached to more than one task in the plan.
-
.verify_no_multiplexing_connections(plan) ⇒ Object
Verifies that there are no multiple output - single input connections towards ports that are not multiplexing ports.
-
.verify_task_allocation(plan) ⇒ Object
Verifies that the task allocation is complete.
Instance Method Summary collapse
-
#allocate_devices(task) ⇒ Object
Try to autoallocate the devices in
task
based on the information in the instance requirements in the task's hierarchy. -
#compute_system_network(instance_requirements, garbage_collect: true, validate_abstract_network: true, validate_generated_network: true) ⇒ Object
Compute in #plan the network needed to fullfill the requirements.
- #find_selected_device_in_hierarchy(argument_name, leaf_task, requirements) ⇒ Object
-
#generate(instance_requirements, garbage_collect: true, validate_abstract_network: true, validate_generated_network: true) ⇒ Hash<Syskit::Component=>Array<InstanceRequirements>>
Generate the network in the plan.
-
#initialize(plan, event_logger: plan.event_logger, merge_solver: MergeSolver.new(plan)) ⇒ SystemNetworkGenerator
constructor
A new instance of SystemNetworkGenerator.
-
#instanciate(instance_requirements) ⇒ void
Create on #plan the task instances that are currently required in #real_plan.
-
#link_to_busses ⇒ Object
Creates communication busses and links the tasks to them.
-
#validate_abstract_network ⇒ Object
Validates the network generated by #compute_system_network.
-
#validate_generated_network ⇒ Object
Validates the network generated by #compute_system_network.
Constructor Details
#initialize(plan, event_logger: plan.event_logger, merge_solver: MergeSolver.new(plan)) ⇒ SystemNetworkGenerator
Returns a new instance of SystemNetworkGenerator
16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 16 def initialize(plan, event_logger: plan.event_logger, merge_solver: MergeSolver.new(plan)) if merge_solver.plan != plan raise ArgumentError, "gave #{merge_solver} as merge solver, which applies on #{merge_solver.plan}. Was expecting #{plan}" end @plan = plan @event_logger = event_logger @merge_solver = merge_solver end |
Instance Attribute Details
#event_logger ⇒ Object (readonly)
Returns the value of attribute event_logger
13 14 15 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 13 def event_logger @event_logger end |
#merge_solver ⇒ Object (readonly)
Returns the value of attribute merge_solver
14 15 16 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 14 def merge_solver @merge_solver end |
#plan ⇒ Object (readonly)
Returns the value of attribute plan
12 13 14 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 12 def plan @plan end |
Class Method Details
.remove_abstract_composition_optional_children(plan) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 154 def self.remove_abstract_composition_optional_children(plan) # Now remove the optional, non-resolved children of compositions plan.find_local_tasks(AbstractComponent).abstract.each do |task| parent_tasks = task.each_parent_task.to_a parent_tasks.each do |parent_task| next if !parent_task.kind_of?(Syskit::Composition) next if parent_task.abstract? roles = parent_task.roles_of(task).dup remaining_roles = roles.find_all do |child_role| !(child_model = parent_task.model.find_child(child_role)) || !child_model.optional? end if remaining_roles.empty? parent_task.remove_child(task) else parent_task.remove_roles(task, *(roles - remaining_roles)) end end end end |
.verify_device_allocation(plan) ⇒ Object
Verifies that all tasks that are device drivers have at least one device attached, and that the same device is not attached to more than one task in the plan
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 289 def self.verify_device_allocation(plan) components = plan.find_local_tasks(Syskit::Device).to_a # Check that all devices are properly assigned missing_devices = components.find_all do |t| t.model.each_master_driver_service. any? { |srv| !t.find_device_attached_to(srv) } end if !missing_devices.empty? raise DeviceAllocationFailed.new(plan, missing_devices), "could not allocate devices for the following tasks: #{missing_devices}" end devices = Hash.new components.each do |task| task.each_master_device do |dev| device_name = dev.full_name if old_task = devices[device_name] raise ConflictingDeviceAllocation.new(dev, task, old_task) else devices[device_name] = task end end end end |
.verify_no_multiplexing_connections(plan) ⇒ Object
Verifies that there are no multiple output - single input connections towards ports that are not multiplexing ports
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 262 def self.verify_no_multiplexing_connections(plan) task_contexts = plan.find_local_tasks(TaskContext).to_a task_contexts.each do |task| seen = Hash.new task.each_concrete_input_connection do |source_task, source_port, sink_port, _| if (port_model = task.model.find_input_port(sink_port)) && port_model.multiplexes? next elsif seen[sink_port] seen_task, seen_port = seen[sink_port] if [source_task, source_port] != [seen_task, seen_port] raise SpecError, "#{task}.#{sink_port} is connected multiple times, at least to #{source_task}.#{source_port} and #{seen_task}.#{seen_port}" end end seen[sink_port] = [source_task, source_port] end end end |
.verify_task_allocation(plan) ⇒ Object
Verifies that the task allocation is complete
247 248 249 250 251 252 253 254 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 247 def self.verify_task_allocation(plan) components = plan.find_local_tasks(AbstractComponent) still_abstract = components.find_all(&:abstract?) if !still_abstract.empty? raise TaskAllocationFailed.new(self, still_abstract), "could not find implementation for the following abstract tasks: #{still_abstract}" end end |
Instance Method Details
#allocate_devices(task) ⇒ Object
Try to autoallocate the devices in task
based on the
information in the instance requirements in the task's hierarchy
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 67 def allocate_devices(task) Engine.debug do Engine.debug "allocating devices on #{task} using" break end task.model.each_master_driver_service do |srv| next if task.find_device_attached_to(srv) if dev = find_selected_device_in_hierarchy(:"#{srv.name}_dev", task, srv.model.to_instance_requirements) Engine.debug do Engine.debug " selected #{dev} for #{srv.name}" end task.arguments[:"#{srv.name}_dev"] = dev end end end |
#compute_system_network(instance_requirements, garbage_collect: true, validate_abstract_network: true, validate_generated_network: true) ⇒ Object
Compute in #plan the network needed to fullfill the requirements
This network is neither validated nor tied to actual deployments
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 178 def compute_system_network(instance_requirements, garbage_collect: true, validate_abstract_network: true, validate_generated_network: true) toplevel_tasks = log_timepoint_group 'instanciate' do instanciate(instance_requirements) end merge_solver.merge_identical_tasks log_timepoint 'merge' Engine.instanciated_network_postprocessing.each do |block| block.call(self, plan) log_timepoint "postprocessing:#{block}" end link_to_busses log_timepoint 'link_to_busses' merge_solver.merge_identical_tasks log_timepoint 'merge' self.class.remove_abstract_composition_optional_children(plan) log_timepoint 'remove-optional' # Finally, select 'default' as configuration for all # remaining tasks that do not have a 'conf' argument set plan.find_local_tasks(Component). each do |task| task.freeze_delayed_arguments end log_timepoint 'default_conf' # Cleanup the remainder of the tasks that are of no use right # now (mostly devices) if garbage_collect plan.static_garbage_collect do |obj| debug { " removing #{obj}" } # Remove tasks that we just added and are not # useful anymore plan.remove_task(obj) end log_timepoint 'static_garbage_collect' end # And get rid of the 'permanent' marking we use to be able to # run static_garbage_collect plan.each_task do |task| plan.unmark_permanent_task(task) end Engine.system_network_postprocessing.each do |block| block.call(self) end log_timepoint 'postprocessing' if validate_abstract_network self.validate_abstract_network log_timepoint 'validate_abstract_network' end if validate_generated_network self.validate_generated_network log_timepoint 'validate_generated_network' end toplevel_tasks end |
#find_selected_device_in_hierarchy(argument_name, leaf_task, requirements) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 48 def find_selected_device_in_hierarchy(argument_name, leaf_task, requirements) _, model, _ = leaf_task.requirements.resolved_dependency_injection.selection_for(nil, requirements) if model && dev = model.arguments[argument_name] return dev else devices = Set.new leaf_task.each_parent_task do |parent| if sel = find_selected_device_in_hierarchy(argument_name, parent, requirements) devices << sel end end if devices.size == 1 return devices.first end end end |
#generate(instance_requirements, garbage_collect: true, validate_abstract_network: true, validate_generated_network: true) ⇒ Hash<Syskit::Component=>Array<InstanceRequirements>>
Generate the network in the plan
33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 33 def generate(instance_requirements, garbage_collect: true, validate_abstract_network: true, validate_generated_network: true) # We first generate a non-deployed network that fits all # requirements. log_timepoint_group 'compute_system_network' do compute_system_network(instance_requirements, garbage_collect: garbage_collect, validate_abstract_network: validate_abstract_network, validate_generated_network: validate_generated_network) end end |
#instanciate(instance_requirements) ⇒ void
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 91 def instanciate(instance_requirements) log_timepoint "instanciate_requirements" toplevel_tasks = instance_requirements.each_with_index.map do |requirements, i| task = requirements.instanciate(plan). to_task # We add all these tasks as permanent tasks, to use # #static_garbage_collect to cleanup #plan. plan.add_permanent_task(task) fullfilled_task_m, fullfilled_modules, fullfilled_args = requirements.fullfilled_model fullfilled_args = fullfilled_args.each_key.inject(Hash.new) do |h, arg_name| if task.arguments.set?(arg_name) h[arg_name] = task.arguments[arg_name] end h end task.fullfilled_model = [fullfilled_task_m, fullfilled_modules, fullfilled_args] log_timepoint "task-#{i}" task end plan.each_task do |task| if task.respond_to?(:each_master_driver_service) allocate_devices(task) end end log_timepoint 'device_allocation' Engine.instanciation_postprocessing.each do |block| block.call(self, plan) log_timepoint "postprocessing:#{block}" end toplevel_tasks end |
#link_to_busses ⇒ Object
Creates communication busses and links the tasks to them
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 125 def link_to_busses # Get all the tasks that need at least one communication bus candidates = plan.find_local_tasks(Syskit::Device). inject(Hash.new) do |h, t| required_busses = t.each_master_device.inject(Array.new) do |list, dev| list + dev.com_busses end.to_set if !required_busses.empty? h[t] = required_busses end h end bus_tasks = Hash.new candidates.each do |task, needed_busses| needed_busses.each do |bus_device| com_bus_task = bus_tasks[bus_device] || bus_device.instanciate(plan) bus_tasks[bus_device] ||= com_bus_task com_bus_task = com_bus_task.component com_bus_task.attach(task) task.depends_on com_bus_task task.should_configure_after com_bus_task.start_event end end nil end |
#validate_abstract_network ⇒ Object
Validates the network generated by #compute_system_network
It performs the tests that are only needed on an abstract network, i.e. on a network in which some tasks are still abstract
319 320 321 322 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 319 def validate_abstract_network self.class.verify_no_multiplexing_connections(plan) super if defined? super end |
#validate_generated_network ⇒ Object
Validates the network generated by #compute_system_network
325 326 327 328 329 |
# File 'lib/syskit/network_generation/system_network_generator.rb', line 325 def validate_generated_network self.class.verify_task_allocation(plan) self.class.verify_device_allocation(plan) super if defined? super end |