Skip to content

Commit 96856f8

Browse files
committed
re-use most of the previous implementation for the fallback implementation
1 parent 1e29450 commit 96856f8

2 files changed

Lines changed: 173 additions & 153 deletions

File tree

loopy/schedule/__init__.py

Lines changed: 169 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
from pytools import ImmutableRecord
2525
import sys
26+
import islpy as isl
2627
from loopy.diagnostic import warn_with_kernel, LoopyError # noqa
2728

2829
from pytools import MinRecursionLimit, ProcessLogger
@@ -214,24 +215,40 @@ def find_loop_nest_around_map(kernel):
214215
"""Returns a dictionary mapping inames to other inames that are
215216
always nested around them.
216217
"""
217-
from collections import defaultdict
218-
from loopy.schedule.tools import get_loop_nest_tree
218+
result = {}
219+
220+
all_inames = kernel.all_inames()
219221

220-
tree = get_loop_nest_tree(kernel)
222+
iname_to_insns = kernel.iname_to_insns()
221223

222-
loop_nest_around_map = defaultdict(frozenset)
224+
# examine pairs of all inames--O(n**2), I know.
225+
from loopy.kernel.data import IlpBaseTag
226+
for inner_iname in all_inames:
227+
result[inner_iname] = set()
228+
for outer_iname in all_inames:
229+
if inner_iname == outer_iname:
230+
continue
223231

224-
for node in tree.all_nodes_itr():
225-
if node.identifier == tree.root:
226-
continue
227-
iname = node.identifier
228-
depth = tree.depth(iname)
229-
all_ancestors = frozenset(tree.ancestor(iname, d).identifier
230-
for d in range(1, depth))
232+
if kernel.iname_tags_of_type(outer_iname, IlpBaseTag):
233+
# ILP tags are special because they are parallel tags
234+
# and therefore 'in principle' nest around everything.
235+
# But they're realized by the scheduler as a loop
236+
# at the innermost level, so we'll cut them some
237+
# slack here.
238+
continue
239+
240+
if iname_to_insns[inner_iname] < iname_to_insns[outer_iname]:
241+
result[inner_iname].add(outer_iname)
242+
243+
for dom_idx, dom in enumerate(kernel.domains):
244+
for outer_iname in dom.get_var_names(isl.dim_type.param):
245+
if outer_iname not in all_inames:
246+
continue
231247

232-
loop_nest_around_map[iname] = all_ancestors
248+
for inner_iname in dom.get_var_names(isl.dim_type.set):
249+
result[inner_iname].add(outer_iname)
233250

234-
return loop_nest_around_map
251+
return result
235252

236253

237254
def find_loop_insn_dep_map(kernel, loop_nest_with_map, loop_nest_around_map):
@@ -802,17 +819,24 @@ def _get_dep_equivalent_nests(tree, within1, within2):
802819
return iname1, iname2
803820

804821

822+
class V2SchedulerNotImplementedException(RuntimeError):
823+
pass
824+
825+
805826
def generate_loop_schedules_v2(kernel):
806827
from loopy.schedule.tools import get_loop_nest_tree
807828
from functools import reduce
808829
from pytools.graph import compute_topological_order
809830
from loopy.kernel.data import ConcurrentTag, IlpBaseTag, VectorizeTag
810831

811832
if any(insn.priority != 0 for insn in kernel.instructions):
812-
raise NotImplementedError
833+
raise V2SchedulerNotImplementedException("v2 scheduler cannot schedule"
834+
" kernels with instruction priorities set.")
813835

814836
if kernel.schedule is not None:
815-
raise NotImplementedError
837+
# cannnot handle preschedule yet
838+
raise V2SchedulerNotImplementedException("v2 scheduler cannot schedule"
839+
" prescheduled kernels.")
816840

817841
concurrent_inames = {iname for iname in kernel.all_inames()
818842
if kernel.iname_tags_of_type(iname, ConcurrentTag)}
@@ -2074,154 +2098,147 @@ def generate_loop_schedules_inner(kernel, debug_args={}):
20742098
from loopy.check import pre_schedule_checks
20752099
pre_schedule_checks(kernel)
20762100

2077-
can_v2_scheduler_handle = (
2078-
# v2-scheduler cannot handle insn groups
2079-
all(len(insn.conflicts_with_groups) == 0
2080-
for insn in kernel.instructions)
2081-
# v2-scheduler cannot handle prescheduled kernel
2082-
and (not kernel.schedule)
2083-
# v2-scheduler cannot handle instruction priorities
2084-
and all(insn.priority == 0
2085-
for insn in kernel.instructions)
2086-
)
2087-
2088-
if can_v2_scheduler_handle:
2101+
try:
20892102
gen_sched = generate_loop_schedules_v2(kernel)
20902103
yield postprocess_schedule(kernel, gen_sched)
2091-
else:
2092-
schedule_count = 0
2093-
2094-
debug = ScheduleDebugger(**debug_args)
2095-
2096-
preschedule = (kernel.schedule
2097-
2098-
if kernel.state == KernelState.LINEARIZED
2099-
2100-
else ())
2101-
2102-
prescheduled_inames = {
2103-
insn.iname
2104-
for insn in preschedule
2105-
if isinstance(insn, EnterLoop)}
2106-
2107-
prescheduled_insn_ids = {
2108-
insn_id
2109-
for item in preschedule
2110-
for insn_id in sched_item_to_insn_id(item)}
2111-
2112-
from loopy.kernel.data import (IlpBaseTag, ConcurrentTag, VectorizeTag,
2113-
filter_iname_tags_by_type)
2114-
ilp_inames = {
2115-
name
2116-
for name, iname in kernel.inames.items()
2117-
if filter_iname_tags_by_type(iname.tags, IlpBaseTag)}
2118-
vec_inames = {
2119-
name
2120-
for name, iname in kernel.inames.items()
2121-
if filter_iname_tags_by_type(iname.tags, VectorizeTag)}
2122-
parallel_inames = {
2123-
name
2124-
for name, iname in kernel.inames.items()
2125-
if filter_iname_tags_by_type(iname.tags, ConcurrentTag)}
2126-
2127-
loop_nest_with_map = find_loop_nest_with_map(kernel)
2128-
loop_nest_around_map = find_loop_nest_around_map(kernel)
2129-
sched_state = SchedulerState(
2130-
kernel=kernel,
2131-
loop_nest_around_map=loop_nest_around_map,
2132-
loop_insn_dep_map=find_loop_insn_dep_map(
2133-
kernel,
2134-
loop_nest_with_map=loop_nest_with_map,
2135-
loop_nest_around_map=loop_nest_around_map),
2136-
breakable_inames=ilp_inames,
2137-
ilp_inames=ilp_inames,
2138-
vec_inames=vec_inames,
2139-
2140-
prescheduled_inames=prescheduled_inames,
2141-
prescheduled_insn_ids=prescheduled_insn_ids,
2142-
2143-
# time-varying part
2144-
active_inames=(),
2145-
entered_inames=frozenset(),
2146-
enclosing_subkernel_inames=(),
2147-
2148-
schedule=(),
2149-
2150-
unscheduled_insn_ids={insn.id for insn in kernel.instructions},
2151-
scheduled_insn_ids=frozenset(),
2152-
within_subkernel=kernel.state != KernelState.LINEARIZED,
2153-
may_schedule_global_barriers=True,
2154-
2155-
preschedule=preschedule,
2156-
insn_ids_to_try=None,
2157-
2158-
# ilp and vec are not parallel for the purposes of the scheduler
2159-
parallel_inames=parallel_inames - ilp_inames - vec_inames,
2160-
2161-
group_insn_counts=group_insn_counts(kernel),
2162-
active_group_counts={},
2163-
2164-
insns_in_topologically_sorted_order=(
2165-
get_insns_in_topologically_sorted_order(kernel)),
2166-
)
2167-
2168-
schedule_gen_kwargs = {}
2169-
2170-
def print_longest_dead_end():
2171-
if debug.interactive:
2172-
print("Loopy will now show you the scheduler state at the point")
2173-
print("where the longest (dead-end) schedule was generated, in the")
2174-
print("the hope that some of this makes sense and helps you find")
2175-
print("the issue.")
2176-
print()
2177-
print("To disable this interactive behavior, pass")
2178-
print(" debug_args=dict(interactive=False)")
2179-
print("to generate_loop_schedules().")
2180-
print(75*"-")
2181-
input("Enter:")
2182-
print()
2183-
print()
2184-
2185-
debug.debug_length = len(debug.longest_rejected_schedule)
2186-
while True:
2187-
try:
2188-
for _ in generate_loop_schedules_internal(
2189-
sched_state, debug=debug, **schedule_gen_kwargs):
2190-
pass
2191-
2192-
except ScheduleDebugInput as e:
2193-
debug.debug_length = int(str(e))
2194-
continue
2104+
return
2105+
except V2SchedulerNotImplementedException as e:
2106+
from warnings import warn
2107+
warn(f"Falling back to a slow scheduler implementation due to: {e}")
21952108

2196-
break
2109+
schedule_count = 0
21972110

2198-
try:
2199-
for gen_sched in generate_loop_schedules_internal(
2200-
sched_state, debug=debug, **schedule_gen_kwargs):
2201-
debug.stop()
2111+
debug = ScheduleDebugger(**debug_args)
2112+
2113+
preschedule = (kernel.schedule
2114+
2115+
if kernel.state == KernelState.LINEARIZED
2116+
2117+
else ())
2118+
2119+
prescheduled_inames = {
2120+
insn.iname
2121+
for insn in preschedule
2122+
if isinstance(insn, EnterLoop)}
2123+
2124+
prescheduled_insn_ids = {
2125+
insn_id
2126+
for item in preschedule
2127+
for insn_id in sched_item_to_insn_id(item)}
2128+
2129+
from loopy.kernel.data import (IlpBaseTag, ConcurrentTag, VectorizeTag,
2130+
filter_iname_tags_by_type)
2131+
ilp_inames = {
2132+
name
2133+
for name, iname in kernel.inames.items()
2134+
if filter_iname_tags_by_type(iname.tags, IlpBaseTag)}
2135+
vec_inames = {
2136+
name
2137+
for name, iname in kernel.inames.items()
2138+
if filter_iname_tags_by_type(iname.tags, VectorizeTag)}
2139+
parallel_inames = {
2140+
name
2141+
for name, iname in kernel.inames.items()
2142+
if filter_iname_tags_by_type(iname.tags, ConcurrentTag)}
2143+
2144+
loop_nest_with_map = find_loop_nest_with_map(kernel)
2145+
loop_nest_around_map = find_loop_nest_around_map(kernel)
2146+
sched_state = SchedulerState(
2147+
kernel=kernel,
2148+
loop_nest_around_map=loop_nest_around_map,
2149+
loop_insn_dep_map=find_loop_insn_dep_map(
2150+
kernel,
2151+
loop_nest_with_map=loop_nest_with_map,
2152+
loop_nest_around_map=loop_nest_around_map),
2153+
breakable_inames=ilp_inames,
2154+
ilp_inames=ilp_inames,
2155+
vec_inames=vec_inames,
2156+
2157+
prescheduled_inames=prescheduled_inames,
2158+
prescheduled_insn_ids=prescheduled_insn_ids,
2159+
2160+
# time-varying part
2161+
active_inames=(),
2162+
entered_inames=frozenset(),
2163+
enclosing_subkernel_inames=(),
2164+
2165+
schedule=(),
2166+
2167+
unscheduled_insn_ids={insn.id for insn in kernel.instructions},
2168+
scheduled_insn_ids=frozenset(),
2169+
within_subkernel=kernel.state != KernelState.LINEARIZED,
2170+
may_schedule_global_barriers=True,
2171+
2172+
preschedule=preschedule,
2173+
insn_ids_to_try=None,
22022174

2203-
new_kernel = postprocess_schedule(kernel, gen_sched)
2204-
yield new_kernel
2175+
# ilp and vec are not parallel for the purposes of the scheduler
2176+
parallel_inames=parallel_inames - ilp_inames - vec_inames,
22052177

2206-
debug.start()
2178+
group_insn_counts=group_insn_counts(kernel),
2179+
active_group_counts={},
22072180

2208-
schedule_count += 1
2181+
insns_in_topologically_sorted_order=(
2182+
get_insns_in_topologically_sorted_order(kernel)),
2183+
)
22092184

2210-
except KeyboardInterrupt:
2185+
schedule_gen_kwargs = {}
2186+
2187+
def print_longest_dead_end():
2188+
if debug.interactive:
2189+
print("Loopy will now show you the scheduler state at the point")
2190+
print("where the longest (dead-end) schedule was generated, in the")
2191+
print("the hope that some of this makes sense and helps you find")
2192+
print("the issue.")
22112193
print()
2194+
print("To disable this interactive behavior, pass")
2195+
print(" debug_args=dict(interactive=False)")
2196+
print("to generate_loop_schedules().")
22122197
print(75*"-")
2213-
print("Interrupted during scheduling")
2214-
print(75*"-")
2215-
print_longest_dead_end()
2216-
raise
2198+
input("Enter:")
2199+
print()
2200+
print()
22172201

2218-
debug.done_scheduling()
2219-
if not schedule_count:
2220-
print(75*"-")
2221-
print("ERROR: Sorry--loopy did not find a schedule for your kernel.")
2222-
print(75*"-")
2223-
print_longest_dead_end()
2224-
raise RuntimeError("no valid schedules found")
2202+
debug.debug_length = len(debug.longest_rejected_schedule)
2203+
while True:
2204+
try:
2205+
for _ in generate_loop_schedules_internal(
2206+
sched_state, debug=debug, **schedule_gen_kwargs):
2207+
pass
2208+
2209+
except ScheduleDebugInput as e:
2210+
debug.debug_length = int(str(e))
2211+
continue
2212+
2213+
break
2214+
2215+
try:
2216+
for gen_sched in generate_loop_schedules_internal(
2217+
sched_state, debug=debug, **schedule_gen_kwargs):
2218+
debug.stop()
2219+
2220+
new_kernel = postprocess_schedule(kernel, gen_sched)
2221+
yield new_kernel
2222+
2223+
debug.start()
2224+
2225+
schedule_count += 1
2226+
2227+
except KeyboardInterrupt:
2228+
print()
2229+
print(75*"-")
2230+
print("Interrupted during scheduling")
2231+
print(75*"-")
2232+
print_longest_dead_end()
2233+
raise
2234+
2235+
debug.done_scheduling()
2236+
if not schedule_count:
2237+
print(75*"-")
2238+
print("ERROR: Sorry--loopy did not find a schedule for your kernel.")
2239+
print(75*"-")
2240+
print_longest_dead_end()
2241+
raise RuntimeError("no valid schedules found")
22252242

22262243
logger.info("%s: schedule done" % kernel.name)
22272244

loopy/schedule/tools.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,10 @@ def _update_flow_requirements(priorities, cannot_satisfy_callback):
221221
# inner iname and outer iname are indirect family members
222222
# => must be realized via dependencies in the linearization
223223
# phase
224-
raise NotImplementedError
224+
from loopy.schedule import V2SchedulerNotImplementedException
225+
raise V2SchedulerNotImplementedException("cannot"
226+
" schedule kernels with priority dependencies"
227+
" between sibling loop nests")
225228

226229
def _raise_loopy_err(x):
227230
raise LoopyError(x)

0 commit comments

Comments
 (0)