Source code for pypdevs.relocators.basicBoundaryRelocator
# Copyright 2014 Modelling, Simulation and Design Lab (MSDL) at
# McGill University and the University of Antwerp (http://msdl.cs.mcgill.ca/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from pypdevs.relocators.boundaryRelocator import BoundaryRelocator
from heapq import heappop, heappush, heapify
[docs]class BasicBoundaryRelocator(BoundaryRelocator):
"""
Basic implementation of a boundary relocator
"""
[docs] def __init__(self, swappiness):
"""
Constructor
:param swappiness: the swappiness
"""
BoundaryRelocator.__init__(self)
self.swappiness = swappiness
[docs] def setController(self, controller):
"""
Configures the controller of this relocator
:param controller: the controller
"""
BoundaryRelocator.setController(self, controller)
[docs] def getRelocations(self, gvt, activities, horizon):
"""
Return all pending relocations
:param gvt: current GVT
:param activities: activities being passed on the GVT ring
:param horizon: the time over which the activities were gathered
:returns: all relocations that should be executed
"""
# Clear all 'semi-global' variables
self.relocate = {}
self.model_activities = {}
self.node_activities = [i[1] for i in activities]
avg_activity = sum(self.node_activities) / len(self.node_activities)
reverts = set()
iterlist = [(activity, node)
for node, activity in enumerate(self.node_activities)
if activity > self.swappiness * avg_activity]
heapify(iterlist)
if sum(self.locations) == 0:
self.locations = [model.location for model in self.model_ids]
self.boundaries = [{} for _ in range(self.kernels)]
self.constructBoundaries(self.model_ids)
while iterlist:
# Keep going as long as there are nodes that are overloaded
srcactivity, node = heappop(iterlist)
# Might have changed in the meantime, though NEVER decreased
srcactivity = self.node_activities[node]
# Now 'node' contains the node that has the most activity of all, so try pushing something away
boundaries = self.boundaries[node]
destactivity, mindest = \
min([(self.node_activities[destination], destination)
for destination in boundaries
if boundaries[destination]])
boundary = boundaries[mindest]
source_deviation = srcactivity - avg_activity
destination_deviation = destactivity - avg_activity
original_heuristic = abs(source_deviation) + \
abs(destination_deviation)
move = None
for option in boundary:
# Swapping the model would give us the following new 'heuristic'
model_activity = self.fetchModelActivity(option)
new_heuristic = abs(source_deviation - model_activity) + \
abs(destination_deviation + model_activity)
if new_heuristic < original_heuristic:
move = option.model_id
original_heuristic = new_heuristic
if move is not None:
# Will migrate model 'move' to 'mindest'
self.scheduleMove(move, mindest)
if srcactivity - model_activity > avg_activity:
heappush(iterlist, (srcactivity - model_activity, node))
if destactivity + model_activity > avg_activity:
# The destination now also became overloaded, so push from this node as well
heappush(iterlist, (destactivity + model_activity, mindest))
return self.relocate
[docs] def useLastStateOnly(self):
"""
Determines whether or not the activities of all steps should be accumulated, or only a single state should be used.
:returns: boolean -- True if the relocator works with a single state
"""
return False