Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Where do Executors go? #2

Open
MasonProtter opened this issue Nov 18, 2024 · 0 comments
Open

Where do Executors go? #2

MasonProtter opened this issue Nov 18, 2024 · 0 comments

Comments

@MasonProtter
Copy link
Member

Some transducers (e.g. Cat) do internal reductions inside of their next methods. For example,
upstream Transducers.jl does

struct Cat <: Transducer
end
function next(rf::R_{Cat}, acc, x)
    rf0, itr0 = retransform(inner(rf), asfoldable(x))
    return __foldl__(skipcomplete(rf), acc, itr0)
end

which basically says that foldl(+, Cat(), [[1.0,2.0,3.0], [4.0, 5.0]]; init=0.0) should turn into

acc = 0.0
for v in [[1.0,2.0,3.0], [4.0, 5.0]]
    for x in v # <------ The inner fold performed by `Cat`
		acc += x
	end
end

However, I have been wanting to make whether or not SIMD is enabled an Executor option, and I wanted to pass Executors to __fold__ and dispatch on them. But this creates a problem for things like Cat(), because it means they might lose things like their SIMD execution info.

There's three potential fixes I see here:

  • Make executors transducers. Upstream Transducers.jl actually does this with SIMD already, but it doesn't do it with things like threads or distributed. I don't think I like this because it's not really a transformation of the inner reducing function, and it's also messy to use / support.
  • Make Cat() hold an Executor. E.g. this would mean you'd write fold(+, Cat(executor = SIMDEx()), vov) if you wanted SIMD to be applied in the inner loop. There's some times where this would be nice and make sense, but I think most of the time it'd just be kinda annoying because it'd case a lot of passing around executors.
    • One place this is nice would be that you could write something like fold(+, Cat(executor=ThreadsEx()), vov) to do inner parallelism. I'm not sure how I feel about this though.
  • Make next take an executor option. So this means that instead of having next(rf, acc, x) you'd have next(rf, acc, x, executor), where the executor argument is normally just ignored, but transducers like Cat can forward it to their inner reduction steps.

I think I dont like option 1, and I'm a little unsure about options 2/3. They both have upsides and downsides. We could also do both of 2 and 3, since they're compatible, i.e. if Cat isn't given an executor, then Cat will use the provided one inside of next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant