dace.transformation.subgraph package

Submodules

dace.transformation.subgraph.expansion module

This module contains classes that implement the expansion transformation.

class dace.transformation.subgraph.expansion.MultiExpansion(*args, **kwargs)

Bases: dace.transformation.transformation.SubgraphTransformation

Implements the MultiExpansion transformation. Takes all the lowest scope maps in a given subgraph, for each of these maps splits it into an outer and inner map, where the outer map contains the common ranges of all maps, and the inner map the rest. Map access variables and memlets are changed accordingly

apply(sdfg, map_base_variables=None)

Applies the transformation on the given subgraph. :param sdfg: The SDFG that includes the subgraph.

static can_be_applied(sdfg: dace.sdfg.sdfg.SDFG, subgraph: dace.sdfg.graph.SubgraphView) → bool

Tries to match the transformation on a given subgraph, returning True if this transformation can be applied. :param sdfg: The SDFG that includes the subgraph. :param subgraph: The SDFG or state subgraph to try to apply the

transformation on.
Returns:True if the subgraph can be transformed, or False otherwise.
debug

Debug Mode

expand(sdfg, graph, map_entries, map_base_variables=None)

Expansion into outer and inner maps for each map in a specified set. The resulting outer maps all have same range and indices, corresponding variables and memlets get changed accordingly. The inner map contains the leftover dimensions :param sdfg: Underlying SDFG :param graph: Graph in which we expand :param map_entries: List of Map Entries(Type MapEntry) that we want to expand :param map_base_variables: Optional parameter. List of strings

If None, then expand() searches for the maximal amount of equal map ranges and pushes those and their corresponding loop variables into the outer loop. If specified, then expand() pushes the ranges belonging to the loop iteration variables specified into the outer loop (For instance map_base_variables = [‘i’,’j’] assumes that all maps have common iteration indices i and j with corresponding correct ranges)
properties()
sequential_innermaps

Make all inner maps that arecreated during expansion sequential

dace.transformation.subgraph.gpu_persistent_fusion module

class dace.transformation.subgraph.gpu_persistent_fusion.GPUPersistentKernel(*args, **kwargs)

Bases: dace.transformation.transformation.SubgraphTransformation

This transformation takes a given subgraph of an SDFG and fuses the given states into a single persistent GPU kernel. Before this transformation can be applied the SDFG needs to be transformed to run on the GPU (e.g. with the GPUTransformSDFG transformation).

If applicable the transform removes the selected states from the original SDFG and places a launch state in its place. The removed states will be added to a nested SDFG in the launch state. If necessary guard states will be added in the nested SDFG, in order to make sure global assignments on Interstate edges will be performed in the kernel (this can be disabled with the include_in_assignment property).

The given subgraph needs to fulfill the following properties to be fused:

  • All states in the selected subgraph need to fulfill the following:
    • access only GPU accessible memory
    • all concurrent DFGs inside the state are either sequential or inside a GPU_Device map.
  • the selected subgraph has a single point of entry in the form of a single InterstateEdge entering the subgraph (i.e. there is at most one state (not part of the subgraph) from which the kernel is entered and exactly one state inside the subgraph from which the kernel starts execution)
  • the selected subgraph has a single point of exit in the form of a single state that is entered after the selected subgraph is left (There can be multiple states from which the kernel can be left, but all will leave to the same state outside the subgraph)
apply(sdfg: dace.sdfg.sdfg.SDFG)

Applies the transformation on the given subgraph. :param sdfg: The SDFG that includes the subgraph.

static can_be_applied(sdfg: dace.sdfg.sdfg.SDFG, subgraph: dace.sdfg.graph.SubgraphView)

Tries to match the transformation on a given subgraph, returning True if this transformation can be applied. :param sdfg: The SDFG that includes the subgraph. :param subgraph: The SDFG or state subgraph to try to apply the

transformation on.
Returns:True if the subgraph can be transformed, or False otherwise.
static get_entry_states(sdfg: dace.sdfg.sdfg.SDFG, subgraph)
static get_exit_states(sdfg: dace.sdfg.sdfg.SDFG, subgraph)
include_in_assignment

Wether to include global variable assignments of the edge going into the kernel inside the kernel or have it happen on the outside. If the assignment is needed in the kernel, it needs to be included.

static is_gpu_state(sdfg: dace.sdfg.sdfg.SDFG, state: dace.sdfg.state.SDFGState) → bool
kernel_prefix

Name of the kernel. If no value is given the kerenl will be refrenced as kernel, if a value is given the kernel will be named <kernel_prefix>_kernel. This is useful if multiple kernels are created.

properties()
validate

Validate the sdfg and the nested sdfg

dace.transformation.subgraph.helpers module

Subgraph Transformation Helper API

dace.transformation.subgraph.helpers.common_map_base_ranges(maps: List[dace.sdfg.nodes.Map]) → List[dace.subsets.Range]

Finds a maximal set of ranges that can be found in every instance of the maps in the given list

dace.transformation.subgraph.helpers.find_reassignment(maps: List[dace.sdfg.nodes.Map], map_base_ranges) → Dict[dace.sdfg.nodes.Map, List[T]]

Provided a list of maps and their common base ranges (found via common_map_base_ranges()), for each map greedily assign each loop to an index so that a base range has the same index in every loop. If a loop range of a certain map does not correspond to a common base range, no index is assigned (=-1)

Parameters:
  • maps – List of maps
  • map_base_ranges – Common ranges extracted via common_map_base_ranges()
Returns:

Dict that maps each map to a vector with the same length as number of map loops. The vector contains, in order, an index for each map loop that maps it to a common base range or ‘-1’ if it does not.

dace.transformation.subgraph.helpers.get_outermost_scope_maps(sdfg, graph, subgraph=None, scope_dict=None)

Returns all Map Entries inside of a given subgraph that have the outermost scope. If the underlying subgraph is not connected, there might be multiple locally outermost scopes. In this ambiguous case, the method returns an empty list. If subgraph == None, the whole graph is taken for analysis.

dace.transformation.subgraph.helpers.outermost_scope_from_maps(graph, maps, scope_dict=None)

Returns the outermost scope of a set of given maps. If the underlying maps are not topologically connected to each other, there might be several scopes that are locally outermost. In this case it throws an Exception

dace.transformation.subgraph.helpers.outermost_scope_from_subgraph(graph, subgraph, scope_dict=None)

Returns the outermost scope of a subgraph. If the subgraph is not connected, there might be several scopes that are locally outermost. In this case, it throws an Exception.

dace.transformation.subgraph.helpers.subgraph_from_maps(sdfg, graph, map_entries, scope_children=None)

Given a list of map entries in a single graph, return a subgraph view that includes all nodes inside these maps as well as map entries and exits as well as adjacent nodes.

dace.transformation.subgraph.reduce_expansion module

This module contains classes that implement the reduce-map transformation.

class dace.transformation.subgraph.reduce_expansion.ReduceExpansion(*args, **kwargs)

Bases: dace.transformation.transformation.Transformation

Implements the ReduceExpansion transformation. Expands a Reduce node into inner and outer map components, where the outer map consists of the axes not being reduced. A new reduce node is created inside the inner map. Special cases where e.g reduction identities are not defined and arrays being reduced to already exist are handled on the fly.

apply(sdfg: dace.sdfg.sdfg.SDFG, strict=False)

Splits the data dimension into an inner and outer dimension, where the inner dimension are the reduction axes and the outer axes the complement. Pushes the reduce inside a new map consisting of the complement axes.

static can_be_applied(graph, candidate, expr_index, sdfg, strict=False)

Returns True if this transformation can be applied on the candidate matched subgraph. :param graph: SDFGState object if this Transformation is

single-state, or SDFG object otherwise.
Parameters:
  • candidate – A mapping between node IDs returned from Transformation.expressions and the nodes in graph.
  • expr_index – The list index from Transformation.expressions that was matched.
  • sdfg – If graph is an SDFGState, its parent SDFG. Otherwise should be equal to graph.
  • strict – Whether transformation should run in strict mode.
Returns:

True if the transformation can be applied.

create_in_transient

Create local in-transientin registers

create_out_transient

Create local out-transientin registers

debug

Debug Info

expand(sdfg, graph, reduce_node)

Splits the data dimension into an inner and outer dimension, where the inner dimension are the reduction axes and the outer axes the complement. Pushes the reduce inside a new map consisting of the complement axes.

static expressions()

Returns a list of Graph objects that will be matched in the subgraph isomorphism phase. Used as a pre-pass before calling can_be_applied. :see: Transformation.can_be_applied

static match_to_str(graph, candidate)

Returns a string representation of the pattern match on the candidate subgraph. Used when identifying matches in the console UI.

properties()
reduce_implementation

Reduce implementation of inner reduce. If specified,overrides any existing implementations

reduction_type_identity = {<ReductionType.Sum: 4>: 0, <ReductionType.Product: 5>: 1, <ReductionType.Bitwise_Or: 9>: 0, <ReductionType.Logical_And: 6>: True, <ReductionType.Logical_Or: 8>: False}
reduction_type_update = {<ReductionType.Max: 3>: 'out = max(reduction_in, array_in)', <ReductionType.Min: 2>: 'out = min(reduction_in, array_in)', <ReductionType.Sum: 4>: 'out = reduction_in + array_in', <ReductionType.Product: 5>: 'out = reduction_in * array_in', <ReductionType.Bitwise_And: 7>: 'out = reduction_in & array_in', <ReductionType.Bitwise_Or: 9>: 'out = reduction_in | array_in', <ReductionType.Bitwise_Xor: 11>: 'out = reduction_in ^ array_in', <ReductionType.Logical_And: 6>: 'out = reduction_in and array_in', <ReductionType.Logical_Or: 8>: 'out = reduction_in or array_in', <ReductionType.Logical_Xor: 10>: 'out = reduction_in != array_in'}

dace.transformation.subgraph.subgraph_fusion module

This module contains classes that implement subgraph fusion

class dace.transformation.subgraph.subgraph_fusion.SubgraphFusion(*args, **kwargs)

Bases: dace.transformation.transformation.SubgraphTransformation

Implements the SubgraphFusion transformation. Fuses together the maps contained in the subgraph and pushes inner nodes into a global outer map, creating transients and new connections where necessary.

SubgraphFusion requires all lowest scope level maps in the subgraph to have the same indices and parameter range in every dimension. This can be achieved using the MultiExpansion transformation first. Reductions can also be expanded using ReduceExpansion as a preprocessing step.

adjust_arrays_nsdfg(sdfg, nsdfg, name, nname)

DFS to replace strides and volumes of data that has adjacent nested SDFGs to its access nodes. Needed in a post-processing step during fusion.

apply(sdfg, do_not_override=None, **kwargs)

Applies the transformation on the given subgraph. :param sdfg: The SDFG that includes the subgraph.

static can_be_applied(sdfg: dace.sdfg.sdfg.SDFG, subgraph: dace.sdfg.graph.SubgraphView) → bool

Fusible if 1. Maps have the same access sets and ranges in order 2. Any nodes in between two maps are AccessNodes only, without WCR

There is at most one AccessNode only on a path between two maps, no other nodes are allowed
  1. The exiting memlets’ subsets to an intermediate edge must cover the respective incoming memlets’ subset into the next map. Also, as a limitation, the union of all exiting memlets’ subsets must be contiguous.
static check_topo_feasibility(sdfg, graph, map_entries, intermediate_nodes, out_nodes)

Checks whether given map entries have topological structure so that they could be fused

consolidate

Consolidate edges that enter and exit the fused map.

copy_edge(graph, edge, new_src=None, new_src_conn=None, new_dst=None, new_dst_conn=None, new_data=None, remove_old=False)

Copies an edge going from source to dst. If no destination is specified, the edge is copied with the same destination and port as the original edge, else the edge is copied with the new destination and the new port. If no source is specified, the edge is copied with the same source and port as the original edge, else the edge is copied with the new source and the new port If remove_old is specified, the old edge is removed immediately If new_data is specified, inserts new_data as a memlet, else else makes a deepcopy of the current edges memlet

debug

Show debug info

static find_permutation(map_entries: List[dace.sdfg.nodes.MapEntry]) → Optional[List[int]]

Find permutation between map ranges. :param map_entries: List of map entries :return: None if no such permutation exists, otherwise a dict

that maps each map to a list of indices L such that L[x]’th parameter of each map have the same range.
fuse(sdfg, graph, map_entries, do_not_override=None, **kwargs)

takes the map_entries specified and tries to fuse maps.

all maps have to be extended into outer and inner map (use MapExpansion as a pre-pass)

Arrays that don’t exist outside the subgraph get pushed into the map and their data dimension gets cropped. Otherwise the original array is taken.

For every output respective connections are crated automatically.

Parameters:
  • sdfg – SDFG
  • graph – State
  • map_entries – Map Entries (class MapEntry) of the outer maps which we want to fuse
  • do_not_override – List of data names whose corresponding nodes are fully contained within the subgraph but should not be augmented/transformed nevertheless.
static get_adjacent_nodes(sdfg, graph, map_entries)

For given map entries, finds a set of in, out and intermediate nodes

static get_invariant_dimensions(sdfg, graph, map_entries, map_exits, node)

on a non-fused graph, return a set of indices that correspond to array dimensions that do not change when we are entering maps for an intermediate access node

prepare_intermediate_nodes(sdfg, graph, in_nodes, out_nodes, intermediate_nodes, map_entries, map_exits, do_not_override=[])

For every interemediate node, determines whether it is fully contained in the subgraph and whether it has any out connections and thus transients need to be created

propagate

Propagate memlets of edges that enter and exit the fused map.Disable if this causes problems. (If memlet propagation doesnot work correctly)

properties()
schedule_innermaps

Schedule of inner maps. If none, keeps schedule.

transient_allocation

Storage Location to push transients to that are fully contained within the subgraph.

Module contents

This module initializes the subgraph transformations package.