Esempio n. 1
0
    def __call__(self, expr):
        from hedge.tools import with_object_array_or_scalar, is_zero

        def bind_one(subexpr):
            if is_zero(subexpr):
                return subexpr
            else:
                from hedge.optemplate.primitives import OperatorBinding

                return OperatorBinding(self, subexpr)

        return with_object_array_or_scalar(bind_one, expr)
Esempio n. 2
0
    def get_next_step(self, available_names, done_insns):
        from pytools import all, argmax2
        available_insns = [
                (insn, insn.priority) for insn in self.instructions
                if insn not in done_insns
                and all(dep.name in available_names
                    for dep in insn.get_dependencies())]

        if not available_insns:
            raise self.NoInstructionAvailable

        from pytools import flatten
        discardable_vars = set(available_names) - set(flatten(
            [dep.name for dep in insn.get_dependencies()]
            for insn in self.instructions
            if insn not in done_insns))

        # {{{ make sure results do not get discarded
        from hedge.tools import with_object_array_or_scalar

        from hedge.optemplate.mappers import DependencyMapper
        dm = DependencyMapper(composite_leaves=False)

        def remove_result_variable(result_expr):
            # The extra dependency mapper run is necessary
            # because, for instance, subscripts can make it
            # into the result expression, which then does
            # not consist of just variables.

            for var in dm(result_expr):
                from pymbolic.primitives import Variable
                assert isinstance(var, Variable)
                discardable_vars.discard(var.name)

        with_object_array_or_scalar(remove_result_variable, self.result)
        # }}}

        return argmax2(available_insns), discardable_vars
Esempio n. 3
0
    def get_next_step(self, available_names, done_insns):
        from pytools import all, argmax2
        available_insns = [(insn, insn.priority) for insn in self.instructions
                           if insn not in done_insns and all(
                               dep.name in available_names
                               for dep in insn.get_dependencies())]

        if not available_insns:
            raise self.NoInstructionAvailable

        from pytools import flatten
        discardable_vars = set(available_names) - set(
            flatten([dep.name for dep in insn.get_dependencies()]
                    for insn in self.instructions if insn not in done_insns))

        # {{{ make sure results do not get discarded
        from hedge.tools import with_object_array_or_scalar

        from hedge.optemplate.mappers import DependencyMapper
        dm = DependencyMapper(composite_leaves=False)

        def remove_result_variable(result_expr):
            # The extra dependency mapper run is necessary
            # because, for instance, subscripts can make it
            # into the result expression, which then does
            # not consist of just variables.

            for var in dm(result_expr):
                from pymbolic.primitives import Variable
                assert isinstance(var, Variable)
                discardable_vars.discard(var.name)

        with_object_array_or_scalar(remove_result_variable, self.result)
        # }}}

        return argmax2(available_insns), discardable_vars
Esempio n. 4
0
    def execute(self, exec_mapper, pre_assign_check=None):
        """If we have a saved, static schedule for this instruction stream,
        execute it. Otherwise, punt to the dynamic scheduler below.
        """

        if self.last_schedule is None:
            return self.execute_dynamic(exec_mapper, pre_assign_check)

        context = exec_mapper.context
        id_to_future = {}
        next_future_id = 0

        schedule_is_delay_free = True

        for discardable_vars, insn, new_future_count in self.last_schedule:
            for name in discardable_vars:
                del context[name]

            if isinstance(insn, self.EvaluateFuture):
                future = id_to_future.pop(insn.future_id)
                if not future.is_ready():
                    schedule_is_delay_free = False
                assignments, new_futures = future()
                del future
            else:
                assignments, new_futures = \
                        insn.get_executor_method(exec_mapper)(insn)

            for target, value in assignments:
                if pre_assign_check is not None:
                    pre_assign_check(target, value)

                context[target] = value

            if len(new_futures) != new_future_count:
                raise RuntimeError("static schedule got an unexpected number "
                        "of futures")

            for future in new_futures:
                id_to_future[next_future_id] = future
                next_future_id += 1

        if not schedule_is_delay_free:
            self.last_schedule = None
            self.static_schedule_attempts -= 1

        from hedge.tools import with_object_array_or_scalar
        return with_object_array_or_scalar(exec_mapper, self.result)
Esempio n. 5
0
    def execute(self, exec_mapper, pre_assign_check=None):
        """If we have a saved, static schedule for this instruction stream,
        execute it. Otherwise, punt to the dynamic scheduler below.
        """

        if self.last_schedule is None:
            return self.execute_dynamic(exec_mapper, pre_assign_check)

        context = exec_mapper.context
        id_to_future = {}
        next_future_id = 0

        schedule_is_delay_free = True

        for discardable_vars, insn, new_future_count in self.last_schedule:
            for name in discardable_vars:
                del context[name]

            if isinstance(insn, self.EvaluateFuture):
                future = id_to_future.pop(insn.future_id)
                if not future.is_ready():
                    schedule_is_delay_free = False
                assignments, new_futures = future()
                del future
            else:
                assignments, new_futures = \
                        insn.get_executor_method(exec_mapper)(insn)

            for target, value in assignments:
                if pre_assign_check is not None:
                    pre_assign_check(target, value)

                context[target] = value

            if len(new_futures) != new_future_count:
                raise RuntimeError("static schedule got an unexpected number "
                                   "of futures")

            for future in new_futures:
                id_to_future[next_future_id] = future
                next_future_id += 1

        if not schedule_is_delay_free:
            self.last_schedule = None
            self.static_schedule_attempts -= 1

        from hedge.tools import with_object_array_or_scalar
        return with_object_array_or_scalar(exec_mapper, self.result)
Esempio n. 6
0
 def rhs(t, u, u_neighbor):
     return compiled_op_template(u=u,
             nb_bdry_u=with_object_array_or_scalar(nb_bdry_permute, u_neighbor))
Esempio n. 7
0
 def rhs(t, u, u_neighbor):
     return compiled_op_template(u=u,
                                 nb_bdry_u=with_object_array_or_scalar(
                                     nb_bdry_permute, u_neighbor))
Esempio n. 8
0
        def apply_op(field):
            from hedge.tools import with_object_array_or_scalar

            return with_object_array_or_scalar(lambda f: bound_op(f=f), field)
Esempio n. 9
0
    def __call__(self, expr, type_hints={}):
        from hedge.optemplate.mappers.type_inference import TypeInferrer
        self.typedict = TypeInferrer()(expr, type_hints)

        # {{{ flux batching
        # Fluxes can be evaluated faster in batches. Here, we find flux 
        # batches that we can evaluate together.

        # For each FluxRecord, find the other fluxes its flux depends on.
        flux_queue = self.get_contained_fluxes(expr)
        for fr in flux_queue:
            fr.dependencies = set(sf.flux_expr
                    for sf in self.get_contained_fluxes(fr.flux_expr)) \
                            - set([fr.flux_expr])

        # Then figure out batches of fluxes to evaluate
        self.flux_batches = []
        admissible_deps = set()
        while flux_queue:
            present_batch = set()
            i = 0
            while i < len(flux_queue):
                fr = flux_queue[i]
                if fr.dependencies <= admissible_deps:
                    present_batch.add(fr)
                    flux_queue.pop(i)
                else:
                    i += 1

            if present_batch:
                # bin batched operators by representative operator
                batches_by_repr_op = {}
                for fr in present_batch:
                    batches_by_repr_op[fr.repr_op] = \
                            batches_by_repr_op.get(fr.repr_op, set()) \
                            | set([fr.flux_expr])

                for repr_op, batch in batches_by_repr_op.iteritems():
                    self.flux_batches.append(
                            self.FluxBatch(
                                repr_op=repr_op, 
                                flux_exprs=list(batch)))

                admissible_deps |= set(fr.flux_expr for fr in present_batch)
            else:
                raise RuntimeError("cannot resolve flux evaluation order")

        # }}}

        # Once flux batching is figured out, we also need to know which
        # derivatives are going to be needed, because once the
        # rst-derivatives are available, it's best to calculate the
        # xyz ones and throw the rst ones out. It's naturally good if
        # we can avoid computing (or storing) some of the xyz ones.
        # So figure out which XYZ derivatives of what are needed.

        self.diff_ops = self.collect_diff_ops(expr)

        # Flux exchange also works better when batched.
        self.flux_exchange_ops = self.collect_flux_exchange_ops(expr)

        # Finally, walk the expression and build the code.
        result = IdentityMapper.__call__(self, expr)

        # Then, put the toplevel expressions into variables as well.
        from hedge.tools import with_object_array_or_scalar
        result = with_object_array_or_scalar(self.assign_to_new_var, result)
        return Code(self.aggregate_assignments(self.code, result), result)
Esempio n. 10
0
    def execute_dynamic(self, exec_mapper, pre_assign_check=None):
        """Execute the instruction stream, make all scheduling decisions
        dynamically. Record the schedule in *self.last_schedule*.
        """
        schedule = []

        context = exec_mapper.context

        next_future_id = 0
        futures = []
        done_insns = set()

        force_future = False

        while True:
            insn = None
            discardable_vars = []

            # check futures for completion

            i = 0
            while i < len(futures):
                future = futures[i]
                if force_future or future.is_ready():
                    futures.pop(i)

                    insn = self.EvaluateFuture(future.id)

                    assignments, new_futures = future()
                    force_future = False
                    break
                else:
                    i += 1

                del future

            # if no future got processed, pick the next insn
            if insn is None:
                try:
                    insn, discardable_vars = self.get_next_step(
                            frozenset(context.keys()),
                            frozenset(done_insns))

                except self.NoInstructionAvailable:
                    if futures:
                        # no insn ready: we need a future to complete to continue
                        force_future = True
                    else:
                        # no futures, no available instructions: we're done
                        break
                else:
                    for name in discardable_vars:
                        del context[name]

                    done_insns.add(insn)
                    assignments, new_futures = \
                            insn.get_executor_method(exec_mapper)(insn)

            if insn is not None:
                for target, value in assignments:
                    if pre_assign_check is not None:
                        pre_assign_check(target, value)

                    context[target] = value

                futures.extend(new_futures)

                schedule.append((discardable_vars, insn, len(new_futures)))

                for future in new_futures:
                    future.id = next_future_id
                    next_future_id += 1

        if len(done_insns) < len(self.instructions):
            print "Unreachable instructions:"
            for insn in set(self.instructions) - done_insns:
                print "    ", insn

            raise RuntimeError("not all instructions are reachable"
                    "--did you forget to pass a value for a placeholder?")

        if self.static_schedule_attempts:
            self.last_schedule = schedule

        from hedge.tools import with_object_array_or_scalar
        return with_object_array_or_scalar(exec_mapper, self.result)
Esempio n. 11
0
    def execute_dynamic(self, exec_mapper, pre_assign_check=None):
        """Execute the instruction stream, make all scheduling decisions
        dynamically. Record the schedule in *self.last_schedule*.
        """
        schedule = []

        context = exec_mapper.context

        next_future_id = 0
        futures = []
        done_insns = set()

        force_future = False

        while True:
            insn = None
            discardable_vars = []

            # check futures for completion

            i = 0
            while i < len(futures):
                future = futures[i]
                if force_future or future.is_ready():
                    futures.pop(i)

                    insn = self.EvaluateFuture(future.id)

                    assignments, new_futures = future()
                    force_future = False
                    break
                else:
                    i += 1

                del future

            # if no future got processed, pick the next insn
            if insn is None:
                try:
                    insn, discardable_vars = self.get_next_step(
                        frozenset(context.keys()), frozenset(done_insns))

                except self.NoInstructionAvailable:
                    if futures:
                        # no insn ready: we need a future to complete to continue
                        force_future = True
                    else:
                        # no futures, no available instructions: we're done
                        break
                else:
                    for name in discardable_vars:
                        del context[name]

                    done_insns.add(insn)
                    assignments, new_futures = \
                            insn.get_executor_method(exec_mapper)(insn)

            if insn is not None:
                for target, value in assignments:
                    if pre_assign_check is not None:
                        pre_assign_check(target, value)

                    context[target] = value

                futures.extend(new_futures)

                schedule.append((discardable_vars, insn, len(new_futures)))

                for future in new_futures:
                    future.id = next_future_id
                    next_future_id += 1

        if len(done_insns) < len(self.instructions):
            print "Unreachable instructions:"
            for insn in set(self.instructions) - done_insns:
                print "    ", insn

            raise RuntimeError(
                "not all instructions are reachable"
                "--did you forget to pass a value for a placeholder?")

        if self.static_schedule_attempts:
            self.last_schedule = schedule

        from hedge.tools import with_object_array_or_scalar
        return with_object_array_or_scalar(exec_mapper, self.result)