Closed steven-johnson closed 7 years ago
jrk@ commented:
I definitely like this. It's worth working a few examples, of course, to further develop it. The obvious cases seem to be the camera pipe, and also something where a module would be scheduled differently in different contexts which would historically have been guarded with C++-level ifs (vectorizing an internal stage within a module which is compute_at some level of the module's output, in cases where the module might be inlined into its uses). This seems to do a nice job with the scoping challenge in things like camera pipe, but it's less clear to me if it has an impact on things that need to propagate through downstream uses in the face of inlining, etc.
Just a quick note, but the first order reason we separated generate and schedule is to support auto scheduling.
Also, one of the first things we tell people about Halide is that its main innovation is separation of algorithm and schedule. A goal of separating the two in the program structure was to add clarity around the issue, not make things more difficult to understand. For code where the algorithm is interleaved with scheduling, I've more than once a way to tell which helper functions do scheduling internally and to what degree, so providing some clues in the syntax or layout does strike me as helpful.
I agree that separating them in the program structure would be good, but scheduling must be in the same scope or a nested scope w.r.t the Funcs and Vars that make the algorithm. Putting scheduling into its own method forced all the Funcs and Vars out into class members (where you get silly side-effects, like mandatory trailing underscores), or forces the schedule to be a mutable lambda that slurps up all the names in scope in the generate method (which works OK, but it's a heavy-duty piece of C++). It's more palatable to me to just put the scheduling code back into generate(). That has served us acceptably so far. If we can do that and also solve the deferred scheduling problem, that would be an OK point in the design space, I think.
Ad-hoc helpers need to document what scheduling they do. If we make Generators usable as local components, then the contract is much more clear. They schedule themselves internally parameterized by the ScheduleParams. The ScheduleParams are the explicit scheduling interface to the component.
Not sure what to do about autoscheduling. I think we need more experience with it. E.g. we don't know if human assistance will always be required in practice - there certainly needs to be some piece of code that sets size estimates, which feels like scheduling code to me.
On Thu, Mar 23, 2017 at 3:24 PM, Zalman Stern notifications@github.com wrote:
Also, one of the first things we tell people about Halide is that its main innovation is separation of algorithm and schedule. A goal of separating the two in the program structure was to add clarity around the issue, not make things more difficult to understand. For code where the algorithm is interleaved with scheduling, I've more than once a way to tell which helper functions do scheduling internally and to what degree, so providing some clues in the syntax or layout does strike me as helpful.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/halide/Halide/issues/1940#issuecomment-288879049, or mute the thread https://github.com/notifications/unsubscribe-auth/AAfdRt1Ua8vWKOcl9uo-jx-bLH-UrgJiks5rovEvgaJpZM4MnYQs .
ScheduleParams in scalar types would act as Exprs that get replaced by constant values at the top of lowering
Our belief right now is that we can probably get by with ScheduleParam<any-scalar-type>
and ScheduleParam<LoopLevel>
The first would be pretty straightforward to do (since an Expr can hold every scalar type we care about); there are several ways to implement it, but doing it just as a type of Variable that we can mutate at the top of lower() seems effective.
LoopLevel is a bit more interesting, though, as it doesn't fit into an Expr right now (and probably shouldn't, period), and isn't really a visible part of the IR tree in general IIUC (it gets stored into various special places inside the bowels of Schedule); further, we may also need to have LoopLevel split into wrapper/contents objects (a la Param/Parameter) to allow for mutating the values without requiring a global table.
Re: auto scheduler estimates being scheduling, in the component use cases we were considering, it seemed unlikely one would know the estimates when writing the Generator, so they would either need to be ScheduleParams or some new sort of parameter, or in our initial idea, provided as arguments to a command line tool or build rule. But yes, we're way ahead of actual use and experience here.
See https://github.com/halide/Halide/pull/1955 for a take on this.
Address by #1955
(Hoisted from discussion on PR#1936)
abadams@ said: