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

storage/cmdq: create new signal type for cmd completion signaling #32164

Merged
merged 1 commit into from
Nov 12, 2018

Conversation

nvanbenschoten
Copy link
Member

signal is a type that can signal the completion of an operation.
This is a component of the larger change in #31997.

The type has three benefits over using a channel directly and
closing the channel when the operation completes:

  1. signaled() uses atomics to provide a fast-path for checking
    whether the operation has completed. It is ~75x faster than
    using a channel for this purpose.
  2. the type's channel is lazily initialized when signalChan()
    is called, avoiding the allocation when one is not needed.
  3. because of 2, the type's zero value can be used directly.

Release note: None

@nvanbenschoten nvanbenschoten requested review from a-robinson and a team November 6, 2018 15:16
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@nvanbenschoten
Copy link
Member Author

name                       time/op
Signaled-4                 0.33ns ± 4%
SignalBeforeChan-4         10.5ns ± 7%
SignalAfterChan-4          51.5ns ±51%
InitialChanBeforeSignal-4  84.2ns ±11%
SecondChanBeforeSignal-4   2.64ns ± 6%
InitialChanAfterSignal-4   2.94ns ± 3%
SecondChanAfterSignal-4    2.90ns ±35%
ReadClosedChan-4           24.1ns ± 0%
SingleSelectClosedChan-4   25.6ns ± 3%
DefaultSelectClosedChan-4  25.4ns ± 8%
MultiSelectClosedChan-4     101ns ± 3%
AtomicLoad-4               0.43ns ± 2%

name                       alloc/op
Signaled-4                  0.00B
SignalBeforeChan-4          0.00B
SignalAfterChan-4           0.00B
InitialChanBeforeSignal-4   96.0B ± 0%
SecondChanBeforeSignal-4    0.00B
InitialChanAfterSignal-4    0.00B
SecondChanAfterSignal-4     0.00B
ReadClosedChan-4            0.00B
SingleSelectClosedChan-4    0.00B
DefaultSelectClosedChan-4   0.00B
MultiSelectClosedChan-4     0.00B
AtomicLoad-4                0.00B

name                       allocs/op
Signaled-4                   0.00
SignalBeforeChan-4           0.00
SignalAfterChan-4            0.00
InitialChanBeforeSignal-4    1.00 ± 0%
SecondChanBeforeSignal-4     0.00
InitialChanAfterSignal-4     0.00
SecondChanAfterSignal-4      0.00
ReadClosedChan-4             0.00
SingleSelectClosedChan-4     0.00
DefaultSelectClosedChan-4    0.00
MultiSelectClosedChan-4      0.00
AtomicLoad-4                 0.00

@nvanbenschoten nvanbenschoten force-pushed the nvanbenschoten/cmdqSignal branch from 0da46f8 to 59717fa Compare November 6, 2018 20:18
Copy link
Collaborator

@petermattis petermattis left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained


pkg/storage/cmdq/signal.go, line 38 at r1 (raw file):

//    whether the operation has completed. It is ~75x faster than
//    using a channel for this purpose.
// 2. the type's channel is lazily initialized when signalChan()

s/type/receiver/g


pkg/storage/cmdq/signal.go, line 86 at r1 (raw file):

		close(c)
	}
	return c

The returned channel might not be closed even though the signal has been signaled. This seems like a rare scenario, though I'm wondering if we should close it. I think that can be done by adding another sigHalfClosed state:

if atomic.CompareAndSwapInt32(&s.a, sig. sigHalfClosed) {
  close(c)
  atomic.StoreInt32(&s.a, sigClosed)
} else {
  for atomic.LoadInt32(&s.a) == sigHalfClosed {
    runtime.GoSched()
  }
}

You'd wrap this up in a close() method so it could be shared with signal().

signal is a type that can signal the completion of an operation.

The type has three benefits over using a channel directly and
closing the channel when the operation completes:
1. signaled() uses atomics to provide a fast-path for checking
   whether the operation has completed. It is ~75x faster than
   using a channel for this purpose.
2. the type's channel is lazily initialized when signalChan()
   is called, avoiding the allocation when one is not needed.
3. because of 2, the type's zero value can be used directly.

Release note: None
@nvanbenschoten nvanbenschoten force-pushed the nvanbenschoten/cmdqSignal branch from 59717fa to a08d232 Compare November 11, 2018 20:43
Copy link
Member Author

@nvanbenschoten nvanbenschoten left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained


pkg/storage/cmdq/signal.go, line 38 at r1 (raw file):

Previously, petermattis (Peter Mattis) wrote…

s/type/receiver/g

Done.


pkg/storage/cmdq/signal.go, line 86 at r1 (raw file):

The returned channel might not be closed even though the signal has been signaled.

Is that a problem though? It will be closed immediately after (before signal() returns), and the caller of signalChan will block on the channel either way. It shouldn't be any different than if signalChan is called before signal().

Copy link
Member

@tbg tbg left a comment

Choose a reason for hiding this comment

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

:lgtm:

Reviewed 1 of 2 files at r1, 1 of 1 files at r2.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained

Copy link
Collaborator

@petermattis petermattis left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained


pkg/storage/cmdq/signal.go, line 86 at r1 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

The returned channel might not be closed even though the signal has been signaled.

Is that a problem though? It will be closed immediately after (before signal() returns), and the caller of signalChan will block on the channel either way. It shouldn't be any different than if signalChan is called before signal().

Yeah, I suppose I was overthinking this. Without the atomic the behavior would be the same. Carry on.

@nvanbenschoten
Copy link
Member Author

I never mentioned the motivation for this change in the PR description. With the new approach in #31997, we end up "waiting" on a much larger number of prerequisites while iterating over prerequisites. There are two reasons for this:

  1. we don't actively try to ignore transitive dependencies like we do in the current command queue
  2. we don't eagerly pull out dependencies from the tree under lock before beginning to wait

This means that there's a much better chance that we reach prereq cmds that are already finished while iterating over our btree snapshot. This was beginning to show up on cpu profiles when I was testing with #31997, and a change like this made the issue go away entirely.

TFTRs.

bors r+

craig bot pushed a commit that referenced this pull request Nov 12, 2018
32164: storage/cmdq: create new signal type for cmd completion signaling r=nvanbenschoten a=nvanbenschoten

`signal` is a type that can signal the completion of an operation.
This is a component of the larger change in #31997.

The type has three benefits over using a channel directly and
closing the channel when the operation completes:
1. signaled() uses atomics to provide a fast-path for checking
   whether the operation has completed. It is ~75x faster than
   using a channel for this purpose.
2. the type's channel is lazily initialized when signalChan()
   is called, avoiding the allocation when one is not needed.
3. because of 2, the type's zero value can be used directly.

Release note: None

Co-authored-by: Nathan VanBenschoten <[email protected]>
@craig
Copy link
Contributor

craig bot commented Nov 12, 2018

Build succeeded

@craig craig bot merged commit a08d232 into cockroachdb:master Nov 12, 2018
@nvanbenschoten nvanbenschoten deleted the nvanbenschoten/cmdqSignal branch November 13, 2018 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants