Skip to content
This repository has been archived by the owner on Jan 29, 2025. It is now read-only.

Add support for zero-initializing workgroup memory #2111

Merged
merged 5 commits into from
Jan 25, 2023

Conversation

teoxoy
Copy link
Member

@teoxoy teoxoy commented Nov 3, 2022

closes #53

Possible future optimizations:

  • spread out initialization across workgroup (most useful for arrays)
  • detect user initialization to avoid double initialization

src/back/msl/writer.rs Outdated Show resolved Hide resolved
@teoxoy teoxoy requested a review from jimblandy November 4, 2022 09:13
Copy link
Member

@ErichDonGubler ErichDonGubler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not finished reviewing yet, but so far, this LGTM. I'll see if I can finish this before end-of-week.

nitpick(non-blocking): 1k LoC in a single commit is a lot. I do think there's some opportunity for breaking this up, but fortunately, the candidates for splitting commits look easy (which tends to mean that the impact isn't high, thankfully). I'll try to call them out where I can.

question: Isn't this sort of new functionality the sort of thing we'd want a CHANGELOG entry for? I see that we don't currently have a PR template encouraging this, which might be something I can do a la wgpu.

note: RE: the Path warning: this warning has been fixed with 0197246, which you should catch with a rebase. 🙌🏻

src/back/glsl/mod.rs Show resolved Hide resolved
src/back/glsl/mod.rs Outdated Show resolved Hide resolved
src/back/glsl/mod.rs Outdated Show resolved Hide resolved
src/back/glsl/mod.rs Show resolved Hide resolved
@@ -65,6 +65,7 @@ impl Writer {
annotations: vec![],
flags: options.flags,
bounds_check_policies: options.bounds_check_policies,
zero_initialize_workgroup_memory: options.zero_initialize_workgroup_memory,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought(non-blocking): I feel like using pattern destructuring for data forwarding would be a really good fit for this sort of logic in Self::new and Self::reset. I'm the type that doesn't trust myself without that sort of safety net, tho, so YMMV. 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use destructuring much as I like seeing where the var came from at first glance.
@jimblandy thoughts?

Copy link
Member

@jimblandy jimblandy Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this particular case I kind of wonder if Writer shouldn't just store an Options directly, instead of copying out all of its members. (If someone wants to do this, let's make it a separate PR.)

In the general case, it's true that destructuring requires that every field gets mentioned, and introduces locals that rustc will complain if we don't use—whereas it can't complain about an unread struct field if it's pub. And I definitely like to take advantage of these static safety nets - I'll often ask people to take out _ => ... arms from match statements just so we can be sure that newly variants get consideration at each use.

I think in this case, for Options, it doesn't pay off, primarily because there's only one spot where the Options value is consulted, and it's the same spot that all the other fields are used. So pretty much any implementation flow that works at all is going to arrive at the spot that needs attention. In other words, it doesn't seem especially error-prone. This wouldn't be the case for, say, a new TypeInner variant: those are used all over the place. Or a new BoundsCheckPolicy - those are consumed in a handful of places scattered around each backend.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm going to talk about things 'paying off', then I should say what the cost is: I think it takes a bit longer to read the destructuring version, there are more variables around that could be mixed with other things, and as Teo said, it's less obvious, when looking at a use, what its origin was.

That is, when I see options.bounds_check_policies, I know exactly where it came from, but when I see just bounds_check_policies, it could be an argument, it could have been computed, etc. and I have to guess or go find out.

@jimblandy
Copy link
Member

Possible future optimizations:

* spread out initialization across workgroup (most useful for arrays)

* detect user initialization to avoid double initialization

These are good ideas - could you file an issue for each?

Copy link
Member

@jimblandy jimblandy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked at the SPIR-V back end yet, but I do have one change I want to see, so I'll just post what I have now.

I'd also be happy to see a TypeFlags-based revision, if you want.

src/back/glsl/mod.rs Outdated Show resolved Hide resolved
src/back/glsl/mod.rs Outdated Show resolved Hide resolved
src/back/glsl/mod.rs Show resolved Hide resolved
src/back/hlsl/writer.rs Outdated Show resolved Hide resolved
src/back/msl/writer.rs Outdated Show resolved Hide resolved
src/back/msl/writer.rs Outdated Show resolved Hide resolved
src/back/msl/writer.rs Outdated Show resolved Hide resolved
src/back/msl/writer.rs Outdated Show resolved Hide resolved
@jimblandy
Copy link
Member

Sorry, some of those comments were intended as replies to Erich's questions, but GitHub didn't see it that way so they're kind of out-of-context.

@teoxoy
Copy link
Member Author

teoxoy commented Jan 5, 2023

@ErichDonGubler

nitpick(non-blocking): 1k LoC in a single commit is a lot. I do think there's some opportunity for breaking this up, but fortunately, the candidates for splitting commits look easy (which tends to mean that the impact isn't high, thankfully). I'll try to call them out where I can.

Most changes seem to come from the test snapshots. Will move the barrier code refactor to a separate commit.

question: Isn't this sort of new functionality the sort of thing we'd want a CHANGELOG entry for? I see that we don't currently have a PR template encouraging this, which might be something I can do a la wgpu.

Tbh, I prefer adding the changelog entries when we do a release since I think it results in higher quality changelogs but what could also have the same effect is asking authors to add a changelog entry (same as wgpu) and doing a last pass before a release to make sure the changelog is cohesive.

@teoxoy teoxoy force-pushed the zero_init_workgroup_mem branch 2 times, most recently from 835c055 to e57e951 Compare January 5, 2023 12:49
Copy link
Member

@jimblandy jimblandy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changed the API for backends, so it needs a CHANGELOG.md entry.

Don't all these writes need to be limited to a single invocation? Right now we're writing to all this storage from every invocation, and that's going to be a race and a waste.

src/back/msl/writer.rs Outdated Show resolved Hide resolved
@@ -65,6 +65,7 @@ impl Writer {
annotations: vec![],
flags: options.flags,
bounds_check_policies: options.bounds_check_policies,
zero_initialize_workgroup_memory: options.zero_initialize_workgroup_memory,
Copy link
Member

@jimblandy jimblandy Jan 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this particular case I kind of wonder if Writer shouldn't just store an Options directly, instead of copying out all of its members. (If someone wants to do this, let's make it a separate PR.)

In the general case, it's true that destructuring requires that every field gets mentioned, and introduces locals that rustc will complain if we don't use—whereas it can't complain about an unread struct field if it's pub. And I definitely like to take advantage of these static safety nets - I'll often ask people to take out _ => ... arms from match statements just so we can be sure that newly variants get consideration at each use.

I think in this case, for Options, it doesn't pay off, primarily because there's only one spot where the Options value is consulted, and it's the same spot that all the other fields are used. So pretty much any implementation flow that works at all is going to arrive at the spot that needs attention. In other words, it doesn't seem especially error-prone. This wouldn't be the case for, say, a new TypeInner variant: those are used all over the place. Or a new BoundsCheckPolicy - those are consumed in a handful of places scattered around each backend.

src/back/msl/writer.rs Outdated Show resolved Hide resolved
src/back/spv/mod.rs Outdated Show resolved Hide resolved
Copy link
Member

@jimblandy jimblandy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the only remaining question here is the one I raised above: should we restrict initialization to a single invocation?

src/back/spv/writer.rs Outdated Show resolved Hide resolved
src/back/spv/writer.rs Outdated Show resolved Hide resolved
tests/out/glsl/workgroup-var-init.main.Compute.glsl Outdated Show resolved Hide resolved
@teoxoy teoxoy force-pushed the zero_init_workgroup_mem branch from e57e951 to dfae06f Compare January 9, 2023 18:37
@teoxoy
Copy link
Member Author

teoxoy commented Jan 9, 2023

This changed the API for backends, so it needs a CHANGELOG.md entry.

Yeah, the question is if we want to require updates to the changelog as part of PRs or do it ourselves before a release.

Don't all these writes need to be limited to a single invocation? Right now we're writing to all this storage from every invocation, and that's going to be a race and a waste.

Indeed, pushed a new commit.

@teoxoy teoxoy force-pushed the zero_init_workgroup_mem branch from dfae06f to 5f2f940 Compare January 9, 2023 18:51
@teoxoy teoxoy requested a review from jimblandy January 9, 2023 18:54
Copy link
Member

@jimblandy jimblandy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still need to process the SPIR-V changes, but I did find something in the MSL.

src/back/hlsl/writer.rs Outdated Show resolved Hide resolved
src/back/msl/writer.rs Outdated Show resolved Hide resolved
@teoxoy teoxoy force-pushed the zero_init_workgroup_mem branch from 5f2f940 to 3708326 Compare January 23, 2023 11:30
@teoxoy
Copy link
Member Author

teoxoy commented Jan 23, 2023

@jimblandy I addressed the latest comments.

Copy link
Member

@jimblandy jimblandy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One problem in the validator changes. I'll look at this again first thing tomorrow morning.

src/valid/type.rs Outdated Show resolved Hide resolved
tests/out/analysis/collatz.info.ron Outdated Show resolved Hide resolved
tests/in/padding.param.ron Show resolved Hide resolved
@teoxoy teoxoy force-pushed the zero_init_workgroup_mem branch from 3708326 to 623988c Compare January 24, 2023 10:49
Copy link
Member

@jimblandy jimblandy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

Comment on lines 1262 to 1269
Instruction::variable(pointer_type_id, varying_id, class, None)
.to_words(&mut self.logical_layout.declarations);

self.decorate(
varying_id,
spirv::Decoration::BuiltIn,
&[spirv::BuiltIn::GlobalInvocationId as u32],
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why, but it's a shame that we have to replicate code like this. This is an example of a case where lowering the Naga IR to some intermediate representation before generating SPIR-V would simplify things. But that shouldn't be addressed in this PR.

@teoxoy teoxoy force-pushed the zero_init_workgroup_mem branch from 0458e45 to 827512c Compare January 25, 2023 17:00
@teoxoy teoxoy merged commit c7d0215 into gfx-rs:master Jan 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[meta] shader transformations
3 participants