示例#1
0
 def calculate_function_value(self, call_function_instruction):
     if call_function_instruction.function_name == 'size':
         var_name = call_function_instruction.args[0]
         if var_name not in self.variables:
             raise RuntimeException(
                 "Variable {0} not defined in communication algorithm {1}.".
                 format(var_name, self.algorithm_name))
         value = self.variables[var_name]
         # If tuple element expression
         if len(call_function_instruction.args) > 1:
             if not isinstance(value, TupleExpression):
                 raise RuntimeException(
                     "Variable {0} in communication algorithm {1} is not tuple, it is: {2}."
                     .format(var_name, self.algorithm_name, unicode(value)))
             index = call_function_instruction.args[1]
             if len(value.elements) <= index:
                 raise RuntimeException(
                     "Variable {0} in communication algorithm {1} has "
                     "{2} elements while index {3} is asked.".format(
                         var_name, self.algorithm_name, len(value.elements),
                         index))
             value = value.elements[index]
         return self.context.metrics_manager.get_expression_size(
             value, self.context, self.host)
     elif call_function_instruction.function_name == 'quality':
         if self.link_quality is None:
             raise RuntimeException(
                 "Link quality is undefined in {0} algorithm. ".format(
                     self.algorithm_name))
         return self.link_quality
     raise RuntimeException(
         "Unresolved reference to function {0}() in algorithm {1}.".format(
             call_function_instruction.function_name, self.algorithm_name))
示例#2
0
def _predefined_routing_next_function__populate(call_function_expression,
                                                host,
                                                populator,
                                                context=None):

    topology_name = call_function_expression.arguments[0].identifier

    receiver_function_id_expression = populator.populate(
        call_function_expression.arguments[1], host)
    receiver_function_id_expression = _predefined_id_function__populate(
        receiver_function_id_expression, host, populator)
    receiver_name = getattr(receiver_function_id_expression, '_host_name')

    receiver = None
    for h in context.hosts:
        if h.name == receiver_name:
            receiver = h
            break

    sender = host
    sender_name = sender.name
    if len(call_function_expression.arguments) > 2:
        sender_function_id_expression = populator.populate(
            call_function_expression.arguments[2], host)
        sender_function_id_expression = _predefined_id_function__populate(
            sender_function_id_expression, host, populator)
        sender_name = getattr(sender_function_id_expression, '_host_name')
        if sender_name != sender.name:
            sender = None
            for h in context.hosts:
                if h.name == sender_name:
                    sender = h
                    break

    if sender is None:
        raise RuntimeException("Host '%s' undefined." % sender_name)
    if receiver is None:
        raise RuntimeException("Host '%s' undefined." % receiver_name)

    if sender == receiver:
        next_host = receiver
    else:
        next_host = context.channels_manager.get_router().get_next_hop_host(
            topology_name, sender, receiver)
        if next_host is None:
            raise RuntimeException(
                "The route from host '%s' to host '%s' cannot be found." %
                (sender_name, receiver_name))
    # DEBUG
    # print host.name, ': ', unicode(call_function_expression), ' -> ', next_host.name
    # DEBUG

    id_function = CallFunctionExpression(
        'id', arguments=[IdentifierExpression(next_host.name)])
    setattr(id_function, '_host_name', next_host.name)
    return id_function
示例#3
0
 def _make_rpn(self, expression):
     """ """
     stack = []
     rpn = []
     for token in expression:
         # if operator
         if self._is_operation_token(token):
             while len(stack) > 0:
                 top_operator = stack[len(stack) - 1]
                 # if current operator is left-associative and its order is lower or equal than top operator
                 # or current operator is right-associative and its order is lower than top operator
                 if (token in self.left_associative_operators
                         and self._operator_order(token) <= self._operator_order(top_operator))\
                    or (token in self.right_associative_operators
                         and self._operator_order(token) < self._operator_order(top_operator)):
                     rpn.append(stack.pop())
                 else:
                     break
             stack.append(token)
         elif token == '(':
             stack.append(token)
         elif token == ')':
             found_paran = False
             while len(stack) > 0:
                 top_operator = stack[len(stack) - 1]
                 if top_operator == '(':
                     found_paran = True
                     stack.pop()
                     break
                 else:
                     rpn.append(stack.pop())
             if not found_paran:
                 raise RuntimeException(
                     "Incorrect number of brackets in algorithm {0}.".
                     format(self.algorithm_name))
         else:  # else number
             if isinstance(token, AlgCallFunction):
                 token = self.calculate_function_value(token)
             elif isinstance(token, basestring):
                 if token not in self.variables:
                     raise RuntimeException(
                         "Variable {0} not defined in communication algorithm {1}."
                         .format(token, self.algorithm_name))
                 token = self.variables[token]
             rpn.append(float(token))
     while len(stack) > 0:
         rpn.append(stack.pop())
     return rpn
示例#4
0
    def _get_current_for_communication(self,
                                       context,
                                       host,
                                       channel,
                                       metric,
                                       message,
                                       receiver=None):
        """
        Returns current (in A) of sending/receiving'listening for a message
        """

        if metric['type'] == 'metric':
            metric_value = metric['value']
        elif metric['type'] == 'algorithm':
            algorithm_name = metric['name']
            if not context.algorithms_resolver.has_algorithm(algorithm_name):
                raise RuntimeException(
                    "Communication algorithm {0} undeclared.".format(
                        algorithm_name))

            link_quality = context.channels_manager.get_router(
            ).get_link_quality(channel.tag_name, message.sender, receiver)
            alg = context.algorithms_resolver.get_algorithm(algorithm_name)
            variables = {
                'link_quality': link_quality,
                alg['parameter']: message.expression,
            }
            metric_value = context.algorithms_resolver.calculate(
                context, host, algorithm_name, variables)
        else:
            return 0
        # unit = metric['unit']
        # exact current (only mA)
        return metric_value / 1000.0
示例#5
0
 def are_equal_call_function_expressions(self, left, right):
     if not isinstance(left, CallFunctionExpression) or not isinstance(
             right, CallFunctionExpression):
         raise RuntimeException(
             "Trying to compare predefined functions expressions, but they are not."
         )
     return self.functions_map[left.function_name]['are_equal'](left, right)
示例#6
0
    def wait_for_message(self, request):
        """
        Add host to the queue of hosts waiting for messages.
        Host can wait for many expressions.
        """
        if not self.is_connected_with_host(request.receiver):
            raise RuntimeException(
                "Channel '%s' is not connected with host '%s'." %
                (self.name, request.receiver.name))

        # Check if this request already exists
        existing_request = self.get_existing_request_for_instruction(
            request.receiver, request.instruction)

        # If it does not exist add
        if not existing_request:
            # print 'IN', unicode(self.name), unicode(request.receiver), unicode(request.instruction)
            self._waiting_requests.append(request)
        else:
            # If request exists, check if it is waiting on IN instruction now
            if not existing_request.is_waiting:
                # If it is now (request stays in channel only to fill the buffer) start waiting on this request
                existing_request.start_waiting()

        # Check if request can be bound with expressions
        self._bind_messages_with_receivers()
示例#7
0
 def _calculate_operation(self, operator, left, right):
     """ """
     if operator == '+':
         return left + right
     elif operator == '-':
         return left - right
     elif operator == '*':
         return left * right
     elif operator == '/':
         return left / right
     elif operator == '==':
         return left == right
     elif operator == '!=':
         return left != right
     elif operator == '>=':
         return left >= right
     elif operator == '>':
         return left > right
     elif operator == '<=':
         return left <= right
     elif operator == '<':
         return left < right
     else:
         raise RuntimeException(
             "Incorrect operator {0} of brackets in algorithm {1}.".format(
                 operator, self.algorithm_name))
示例#8
0
 def calculate(self):
     while not self.finished():
         self.execute_current_instruction()
     if self.return_value is None:
         raise RuntimeException(
             "Algorithm {0} has no return value. Did you forget to use return instruction?"
             .format(self.algorithm_name))
     return self.return_value
示例#9
0
    def find_primitive(self, host, call_function_expression):
        """
        Method finds metric for function call in host.
        Method searches the metric in three kinds: normal, plus and star.
        If more than one metrics is found, runtime exception is raised. 
        """
        found_host_metric = None
        for host_metric in self.host_metrics:
            if host_metric.is_connected_with_host(host):
                found_host_metric = host_metric
                break

        if not found_host_metric:
            return None

        normal_metrics = []
        plus_metrics = []
        star_metrics = []

        if len(found_host_metric.normal_blocks) > 0:
            for mb in found_host_metric.normal_blocks:
                if len(mb.params) <= len(
                        call_function_expression.qop_arguments):
                    normal_metrics.extend(
                        mb.find_primitives(
                            call_function_expression.function_name,
                            call_function_expression.qop_arguments))

        if len(found_host_metric.plus_blocks) > 0:
            for mb in found_host_metric.plus_blocks:
                if len(mb.params) <= len(
                        call_function_expression.qop_arguments):
                    plus_metrics.extend(
                        mb.find_primitives(
                            call_function_expression.function_name,
                            call_function_expression.qop_arguments))

        if len(found_host_metric.star_blocks) > 0:
            for mb in found_host_metric.star_blocks:
                if len(mb.params) <= len(
                        call_function_expression.qop_arguments):
                    star_metrics.extend(
                        mb.find_primitives(
                            call_function_expression.function_name,
                            call_function_expression.qop_arguments))

        if len(normal_metrics) + len(plus_metrics) + len(star_metrics) > 1:
            raise RuntimeException("Found many metrics for function '%s' with qopanalysis arguments: %s." \
                                   % (call_function_expression.function_name,
                                      ', '.join(call_function_expression.qop_arguments)))

        if len(normal_metrics) > 0:
            return normal_metrics[0]
        if len(plus_metrics) > 0:
            return plus_metrics[0]
        if len(star_metrics) > 0:
            return star_metrics[0]
        return None
示例#10
0
    def _get_time_for_communication_step(self,
                                         context,
                                         host,
                                         channel,
                                         metric,
                                         message,
                                         receiver=None):
        """ Returns time of sending/receiving message """

        if metric['type'] == 'metric':
            metric_value = metric['value']
        elif metric['type'] == 'algorithm':
            algorithm_name = metric['name']
            if not context.algorithms_resolver.has_algorithm(algorithm_name):
                raise RuntimeException(
                    "Communication algorithm {0} undeclared.".format(
                        algorithm_name))

            link_quality = context.channels_manager.get_router(
            ).get_link_quality(channel.tag_name, message.sender, receiver)
            alg = context.algorithms_resolver.get_algorithm(algorithm_name)
            variables = {
                'link_quality': link_quality,
                alg['parameter']: message.expression,
            }
            metric_value = context.algorithms_resolver.calculate(
                context, host, algorithm_name, variables)
        else:
            return 0

        unit = metric['unit']
        if unit == 'ms':
            # exact time
            return metric_value / 1000.0
        else:
            # time depending on the size
            populated_expression = context.expression_populator.populate(
                message.expression, message.sender)
            # size in bytes
            size = context.metrics_manager.get_expression_size(
                populated_expression, context, message.sender)

            mspB = 0
            if unit == 'mspB':
                mspB = float(metric_value)
            elif unit == 'mspb':
                mspB = float(metric_value) * 8.0
            elif unit == 'kbps':
                mspB = 1.0 / (float(metric_value) * 0.128)
            elif unit == 'mbps':
                mspB = 1.0 / (float(metric_value) * 0.000128)

            spB = mspB / 1000.0

            return spB * size
示例#11
0
 def _operator_order(self, operator):
     """
     Returns the order of operator as number.
     """
     orders = [['==', '!=', '<=', '>=', '>', '<', '&&', '||'],
               ['--', '-', '+'], ['*', '/']]
     for i in range(0, len(orders)):
         if operator in orders[i]:
             return i
     raise RuntimeException(
         "Operator {0} undefined in algorithm {1}.".format(
             operator, self.algorithm_name))
示例#12
0
    def _compute_current_expression(self, expression, context):
        """
        Computes the expression from current assignment instruction.
        """
        if isinstance(expression, BooleanExpression):
            return expression.clone()
        
        if isinstance(expression, IdentifierExpression) or isinstance(expression, CallFunctionExpression) \
                or isinstance(expression, TupleExpression) or isinstance(expression, TupleElementExpression):
            # Population of variables which were previously populated (ie. additional attrs)
            return context.expression_populator.populate(expression, context.get_current_host())

        raise RuntimeException("Expression '%s' cannot be a value of variable.")
示例#13
0
    def fulfill(self):
        """
        Assigns requested variables with received messages.
        """
        if not self.ready_to_fulfill():
            raise RuntimeException(
                "Request of host {0} in instruction {1} is not ready to fulfill."
                .format(self.receiver.name, unicode(self.instruction)))

        # Set variable sent in message
        self.receiver.set_variable(self.instruction.variable_name,
                                   self.assigned_message.expression.clone())

        # Move instructions context to the next instruction
        # print unicode(self.receiver.get_instructions_context_of_instruction(self.instruction).get_current_instruction())
        self.receiver.get_instructions_context_of_instruction(self.instruction)\
            .goto_next_instruction()
        # print unicode(self.receiver.get_instructions_context_of_instruction(self.instruction))
        self.receiver.mark_changed()
示例#14
0
    def execute_instruction(self, context, **kwargs):
        """ Overriden """
        instruction = context.get_current_instruction()
        channel = context.channels_manager.find_channel_for_current_instruction(context)

        if context.channels_manager.find_channel(instruction.channel_name) is None:
            raise RuntimeException("Channel {0} undefined.".format(instruction.channel_name))

        if not channel:
            context.get_current_host().get_current_instructions_context().goto_next_instruction()
            context.get_current_host().mark_changed()
            return ExecutionResult(consumes_cpu=True,
                                   custom_index_management=True)
        
        if instruction.communication_type == COMMUNICATION_TYPE_OUT:
            if kwargs is not None and 'sent_message' in kwargs:
                message = kwargs['sent_message']
            else:
                message = context.channels_manager.build_message(
                    context.get_current_host(),
                    context.get_current_host().get_variable(instruction.variable_name).clone(),
                    context.expression_checker)
                kwargs['sent_message'] = message
            channel.send_message(context.get_current_host(), message, context.channels_manager.get_router())

            # Go to next instruction
            context.get_current_host().get_current_instructions_context().goto_next_instruction()
            context.get_current_host().mark_changed()
            
        else:
            if kwargs is not None and 'messages_request' in kwargs:
                request = kwargs['messages_request']
            else:
                request = context.channels_manager.build_message_request(context.get_current_host(), instruction,
                                                                         context.expression_populator)
                kwargs['messages_request'] = request

            channel.wait_for_message(request)
            
        return ExecutionResult(consumes_cpu=True, 
                               custom_index_management=True,
                               result_kwargs=kwargs)
示例#15
0
    def _execute_hook(self, hook_type):
        """
        Execute all hooks of given type.
        Pre instruction and post instruction hooks 
        cannot be executed manually.
        """

        if hook_type not in self._hooks:
            return

        if hook_type in [
                HOOK_TYPE_PRE_INSTRUCTION_EXECUTION,
                HOOK_TYPE_POST_INSTRUCTION_EXECUTION
        ]:
            raise RuntimeException(
                "Cannot execute pre instruction and post instruction hooks manually."
            )

        for h in self._hooks[hook_type]:
            h.execute(self.context)
示例#16
0
    def send_message(self, sender_host, message, router):
        """
        Accept message with expressions.
        """
        if not self.is_connected_with_host(sender_host):
            raise RuntimeException(
                "Channel '%s' is not connected with host '%s'." %
                (self.name, sender_host.name))

        # print 'OUT', unicode(self.name), unicode(sender_host), unicode(message.expression)

        # Put sent message in the buffers of receivers
        # Receivers are retrieved from the requests present in the channel
        # When the channel is synchronous the buffers are cleaned after the binding try
        # and requests are removed after they are fulfilled
        for request in self.get_filtered_requests(message, router):
            if request.receiver not in self._buffers:
                self._buffers[request.receiver] = []
            self._buffers[request.receiver].append(message)

        # Check if request can be bound with expressions
        self._bind_messages_with_receivers()
示例#17
0
    def get_next_hop_host(self, medium_name, sender, receiver):
        """
        Returns the next host which is in the path between sender and receiver.
        If path does not exist, None is returned.
        """
        # Check if path already exists
        existing_next_hop = self._find_existing_next_hop_host(
            medium_name, sender, receiver)
        if existing_next_hop is not None:
            return existing_next_hop

        # Build path using Dijsktra algorithm
        topology = self.mediums[medium_name]['topology']

        def find_closest_host(distances, out):
            closest_host = None
            d = -1
            for h in distances:
                if d < 0 or d > distances[h]:
                    if h not in out:
                        closest_host = h
                        d = distances[h]
            return closest_host, d

        # Dijsktra
        distances = {sender: 0}
        out = []
        closest, closes_distance = find_closest_host(distances, out)
        while (closest is not None) and (closest != receiver):

            if closest in topology:
                qualities = self.get_sender_links_qualities(
                    medium_name, closest, exclude_broadcast=True)
                for next_host in qualities:
                    if (next_host not in distances) \
                            or ((closes_distance + qualities[next_host]) < distances[next_host]):
                        distances[
                            next_host] = closes_distance + qualities[next_host]
            out.append(closest)
            closest, closes_distance = find_closest_host(distances, out)

        # for h in distances:
        #     print h.name, distances[h]

        def update_paths(medium_name, receiver, distances):
            routing = self.routing[medium_name]
            # Start from receiver
            current_host = receiver
            distance = distances[receiver]
            # Add receiver to path
            hosts_path = [receiver]
            # Repeat until we finish handling sender
            while distance > 0:
                # Find all hosts that are connected with current host
                previous_hosts = self.get_hosts_sending_to_receiver(
                    medium_name, current_host)
                for prev_host in previous_hosts:
                    # If prev host has not calculated distance, omit him
                    if prev_host not in distances:
                        continue
                    # Check if this host is on the shortest path
                    prev_quality = previous_hosts[prev_host]
                    if distances[prev_host] + prev_quality == distances[
                            current_host]:
                        # Go one step earlier
                        current_host = prev_host
                        # Decrease current distance
                        distance = distances[prev_host]
                        if prev_host not in routing:
                            routing[prev_host] = {}
                        next_host = hosts_path[0]
                        if next_host not in routing[prev_host]:
                            routing[prev_host][next_host] = []
                        for i in range(0, len(hosts_path)):
                            routing[prev_host][next_host].append(hosts_path[i])
                        # Add host to path
                        hosts_path.insert(0, prev_host)
                        break

        # Printer().print_routing(self.routing[medium_name])
        if receiver not in distances:
            raise RuntimeException(
                "The path between {0} and {1} undefined.".format(
                    sender.name, receiver.name))

        update_paths(medium_name, receiver, distances)
        return self._find_existing_next_hop_host(medium_name, sender, receiver)
示例#18
0
    def get_expression_size(self, expression, context, host):
        """
        Returns the size in bytes of expression according to metrics.
        Metrics van specify exact size (ie. in bytes, bits, kilobytes, kilobits, megabytes, megabits)
        or ratio size (ie. 0.5 equals 50%) used ie. in compression.
        Expression cannot have variables - it must be filled with variables' values.
        """
        size = 0

        if isinstance(expression, IdentifierExpression):
            # If expression is an variable, get its value size
            return self.get_expression_size(
                host.get_variable(expression.identifier), context, host)

        if isinstance(expression, TupleElementExpression):
            variable = host.get_variable(expression.variable_name)
            variable = context.expression_reducer.reduce(variable)
            if not isinstance(variable, TupleExpression):
                raise RuntimeException(
                    'Cannot get tuple element on expression: %s.' %
                    unicode(variable))
            return self.get_expression_size(
                variable.elements[expression.index], context, host)

        elif isinstance(expression, TupleExpression):
            # If expression is tuple, just sum its elements' sizes
            for expr in expression.elements:
                size += self.get_expression_size(expr, context, host)
            return size

        if isinstance(expression, CallFunctionExpression) or isinstance(
                expression, CallFunctionInstruction):
            expression = context.expression_reducer.reduce(expression)
            metric = self.find_primitive(host, expression)

            if not metric:
                raise RuntimeException(
                    "Cannot get expression size: No metric found for expression '%s'."
                    % unicode(expression))

            block = metric.block
            for i in range(0, len(block.service_params)):
                sparam = block.service_params[i]

                if sparam.service_name.lower() != "size":
                    continue

                metric_type = sparam.param_name.lower()
                metric_unit = sparam.unit
                metric_value = metric.service_arguments[i]

                if metric_type == "ratio":
                    mparts = metric_value.split(':')
                    element_index = int(mparts[0]) - 1
                    percent = float(mparts[1])

                    size = self.get_expression_size(expression.arguments[element_index], context, host) \
                            * percent
                elif metric_type == "sum_ratio":
                    ratios = metric_value.split(',')
                    size = 0.0
                    for ratio in ratios:
                        rparts = ratio.strip().split(':')
                        element_index = int(rparts[0]) - 1
                        percent = float(rparts[1])

                        size += self.get_expression_size(expression.arguments[element_index], context, host) \
                                * percent
                elif metric_type == "exact":
                    if metric_unit == 'B':
                        size = float(metric_value)
                    elif metric_unit == 'b':
                        size = float(metric_value) / 8.0
                    else:
                        raise RuntimeException(
                            'Cannot get expression size: Unsupported size value for exact type.'
                        )

                elif metric_type == "block":
                    mparts = metric_value.split(':')
                    element_index = int(mparts[0]) - 1
                    unit_value = int(mparts[1])

                    factor = 1.0
                    if metric_unit == 'b':
                        factor = 1.0 / 8.0

                    argument_size = self.get_expression_size(
                        expression.arguments[element_index], context, host)
                    argument_size_excess = argument_size % unit_value

                    size = argument_size
                    if argument_size_excess > 0:
                        size += unit_value - argument_size_excess
                    size *= factor

                elif metric_type == "nested":
                    mparts = metric_value.split(':')
                    element_index = int(mparts[0]) - 1
                    nested_element_index = int(mparts[1]) - 1

                    nested_expression = expression.arguments[element_index]

                    if isinstance(nested_expression, IdentifierExpression):
                        nested_expression = host.get_variable(
                            nested_expression.identifier)

                    if not isinstance(nested_expression, CallFunctionExpression) and \
                        not isinstance(nested_expression, CallFunctionInstruction):
                        raise RuntimeException(
                            'Cannot get nested expression size: Not a function call.'
                        )

                    size = self.get_expression_size(
                        nested_expression.arguments[nested_element_index],
                        context, host)

                else:
                    raise RuntimeException(
                        'Cannot get expression size: Unsupported size type.')

                return size
        raise RuntimeException(
            'Cannot get expression size: Unsupported expression type. Expression: {0}.'
            .format(unicode(expression)))
示例#19
0
    def _update_vars_simple(self, context, expression):
        """
        Update reputation variables in host according to call function expression.
        """

        # Firstly update vars according to nested call functions
        for e in expression.arguments:
            self._update_vars(context, e)

        # Now update vars according to current call function
        host = context.get_current_host()
        self._prepare_host_variables(host)

        metric_expression = CallFunctionExpression(expression.function_name,
                                                   expression.arguments, [])
        metric = context.metrics_manager\
            .find_primitive(host, metric_expression)

        if metric:
            block = metric.block

            algorithm_name = None
            for i in range(0, len(block.service_params)):
                sparam = block.service_params[i]

                if sparam.service_name.lower() != "reputation":
                    continue

                metric_type = sparam.param_name.lower()
                metric_value = metric.service_arguments[i]

                if metric_type == "algorithm":
                    algorithm_name = metric_value
                    break

            if algorithm_name:
                algorithm = self.module.get_algorithm(algorithm_name)

                if len(expression.qop_arguments) != len(
                        algorithm['parameters']):
                    raise RuntimeException(
                        'Reputation algorithm "%s" required %d parameters, %d given.'
                        % (algorithm_name, len(algorithm['parameters']),
                           len(expression.qop_arguments)))

                vars = self.module.get_host_vars(host)
                i = 0
                for qop_arg in expression.qop_arguments:
                    try:
                        val = float(qop_arg)
                        vars[algorithm['parameters'][i]] = val
                        i += 1
                    except ValueError:
                        raise RuntimeException(
                            'Reputation argument "%s" in expression "%s" not a float number.'
                            % (qop_arg, unicode(expression)))

                vars = update_vars(host, algorithm['instructions'], vars)

                for var_name in self.module.init_vars:
                    self.module.set_reputation_var(host, var_name,
                                                   vars[var_name])
示例#20
0
    def reduce(self, expression):
        """
        Reduces expression with usage of equations.
        Returns reduced expression.
        Raises exception if ambiguity is found.
        """
        continue_reducing = True
        """     
        # Wrap expression and user wrapper variable
        # Used to simulate real pass-by-reference
        # If expression was passed without wrapped variable and equation wanted to
        # replace whole exception, it would not work, because whole variable cannot be changed
        # For example:
        # eq enc(K, dec(K, X)) = X
        # expression: enc(k(), dec(k(), b()) should be reduced to b()
        # If we pass whole expression variable to reduce we cannot change it whole
        # def f(x,v) -> x = v
        # e = A(a=1)
        # f(e, A(a=2)) - will not work, because e is reference to instance, but passed by value
        # When we pass wrapper, we can change its element (ie. expression)
        """

        # Reduce until no reduction can be performed.
        # One reduction can give way for another reduction.
        while continue_reducing:
            continue_reducing = False

            # For each equation we find points where expression can be reduced
            reduction_points = self._get_reduction_points(expression)

            if len(reduction_points) > 0:

                # For each point:
                #  - temporary reduce at this point
                #  - remove used point from reduction points list
                #  - generate new reduction points list for reduced expression
                #  - if any of points from old list is not present in new list raise ambiguity exception
                #  ! New reduction points may come

                for reduction_point in reduction_points:

                    # Generate list with reduction points before reduction
                    old_reduction_points = copy.copy(reduction_points)
                    old_reduction_points.remove(reduction_point)

                    # Reduce temporary
                    expression = reduction_point.reduce()

                    # Generate new reduction points
                    new_reduction_points = self._get_reduction_points(
                        expression)

                    for old_reduction_point in old_reduction_points:
                        found = False
                        for new_reduction_point in new_reduction_points:
                            if old_reduction_point.equals_to(
                                    new_reduction_point):
                                found = True
                                break
                        if not found:
                            raise RuntimeException(
                                "Equations '%s' and '%s are ambiguous for expression: %s."
                                % (unicode(old_reduction_point.equation),
                                   unicode(reduction_point.equation),
                                   unicode(expression)))

                    # Cancel reduction
                    expression = reduction_point.rollback()

                # Ambiguity error checked

                # Make factual reduction
                reduction_point = reduction_points[0]

                # Reduce and commit reduction
                expression = reduction_point.reduce()

                continue_reducing = True

        return expression
示例#21
0
    def populate(self, expression, host, main_expression=None):
        """
        Returns new expression with replaced variables names 
        with copies of values of variables from variables list.
        Reducer is used for special types of variables, 
        eg. tuple element expressions.
        """
        if main_expression is None:
            main_expression = expression

        variables = host.get_variables()

        if isinstance(expression, IdentifierExpression):
            if expression.identifier not in variables:
                raise RuntimeException(
                    "Variable {0} undefined in expression '{1}'.".format(
                        expression.identifier, unicode(main_expression)))
            return variables[expression.identifier].clone()

        if isinstance(expression, CallFunctionExpression):

            if self.is_function_predefined(expression.function_name):
                populated = self.predefined_functions_manager.populate_call_function_expression_result(
                    expression, host, self)
                return populated.clone()

            arguments = []
            for arg in expression.arguments:
                arguments.append(
                    self.populate(arg, host, main_expression=main_expression))
            qop_arguments = []
            for qop_arg in expression.qop_arguments:
                qop_arguments.append(qop_arg)
            return CallFunctionExpression(expression.function_name, arguments,
                                          qop_arguments)

        if isinstance(expression, TupleExpression):
            elements = []
            for e in expression.elements:
                elements.append(
                    self.populate(e, host, main_expression=main_expression))
            return TupleExpression(elements)

        if isinstance(expression, TupleElementExpression):
            if expression.variable_name not in variables:
                raise RuntimeException(
                    "Variable {0} does not exist in host {1}. Trying expression '{2}'."
                    .format(expression.variable_name, host.name,
                            unicode(main_expression)))
            expr = variables[expression.variable_name]
            if not isinstance(expr, TupleExpression):
                expr = self.reducer.reduce(expr)
            if not isinstance(expr, TupleExpression):
                raise RuntimeException(
                    "Cannot compute expression '{0}' in host {1}. Variable {2} is not a tuple. It is: {3}."
                    .format(unicode(main_expression), host.name,
                            expression.variable_name, unicode(expr)))
            if len(expr.elements) <= expression.index:
                raise RuntimeException(
                    "Cannot compute expression '{0}' in host {1}. "
                    "Variable {2} does not have index {3}. It has {4} elements: {5}."
                    .format(unicode(main_expression), host.name,
                            expression.variable_name, expression.index,
                            len(expr.elements), unicode(expr)))
            return self.populate(expr.elements[expression.index],
                                 host,
                                 main_expression=main_expression)

        return expression.clone()
示例#22
0
 def get_variable(self, name):
     """ Get host's variable """
     if name not in self._variables:
         raise RuntimeException("Variable '%s' undefined in host '%s'." % (name, self.name))
     return self._variables[name]
示例#23
0
    def _get_time_details_for_simple_expression(self, context, expression):
        """
        Calculate time for expression.
        """
        time = 0
        time_details = []

        metric = context.metrics_manager\
            .find_primitive(context.get_current_host(), expression)

        if metric:
            block = metric.block

            for i in range(0, len(block.service_params)):
                sparam = block.service_params[i]

                if sparam.service_name.lower().strip() != "time":
                    continue

                metric_type = sparam.param_name.lower().strip()
                metric_unit = sparam.unit
                metric_value = metric.service_arguments[i].strip()

                if metric_type in ["exact", "range"]:

                    time = self._get_time_for_exact_range_metric(
                        metric_type, metric_unit, metric_value, expression,
                        context.get_current_host(), context)
                elif metric_type == "block":

                    time = self._get_time_for_block_metric(
                        metric_type, metric_unit, metric_value, expression,
                        context.get_current_host(), context)
                elif metric_type == 'algorithm':
                    algorithm_name = metric_value
                    if not context.algorithms_resolver.has_algorithm(
                            algorithm_name):
                        raise RuntimeException(
                            "Communication algorithm {0} undeclared.".format(
                                algorithm_name))

                    alg = context.algorithms_resolver.get_algorithm(
                        algorithm_name)
                    variables = {alg['parameter']: expression}
                    time = context.algorithms_resolver.calculate(
                        context, context.get_current_host(), algorithm_name,
                        variables)

                    # Update time according to the time unit
                    if metric_unit == "ms":
                        time /= 1000.0

            if time > 0:
                time_details.append((expression, time))

        for expr in expression.arguments:
            argument_time, argument_time_details = self._get_time_details_for_expression(
                context, expr)
            time += argument_time
            time_details.extend(argument_time_details)

        return time, time_details