-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
core: don't reschedule idle timer if it is already active #4297
Conversation
} | ||
|
||
/** Time source representing nanoseconds since fixed but arbitrary point in time. */ | ||
interface Ticker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: Guava's ticker is an abstract class, and marked @Beta
. I can't use it here, so I define an interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I toyed with this some (just now) using Stopwatch. I think it ends up fine (no unnecessary now() calls in the normal paths), and it is a stable API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to using stopwatch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good with minor comments.
@@ -293,7 +293,7 @@ public void onPingTimeout() { | |||
public abstract long read(); | |||
} | |||
|
|||
private static class SystemTicker extends Ticker { | |||
static class SystemTicker extends Ticker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted, this was originally going to be reused.
private long runAt; | ||
private boolean enabled; | ||
|
||
Rescheduler(Runnable r, ChannelExecutor exec, ScheduledExecutorService scheduler) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a way to decouple Rescheduler from ChannelExecutor. Pass an Executor
here and make it an requirement that it must serialize its runnables and rechedule()
. In ManagedChannelImpl
, you could make an Executor
that delegates to ChannelExecutor
. I am strong for splitting this class out of ManagedChannelImpl
, which is good for test-ability and also for the fitness of ManagedChannelImpl
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PTAL
private long runAt; | ||
private boolean enabled; | ||
|
||
Rescheduler(Runnable r, ChannelExecutor exec, ScheduledExecutorService scheduler) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
} | ||
|
||
/** Time source representing nanoseconds since fixed but arbitrary point in time. */ | ||
interface Ticker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to using stopwatch.
@@ -293,7 +293,7 @@ public void onPingTimeout() { | |||
public abstract long read(); | |||
} | |||
|
|||
private static class SystemTicker extends Ticker { | |||
static class SystemTicker extends Ticker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted, this was originally going to be reused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please still wait for @zhangkun83's review.
@@ -317,4 +317,4 @@ public long currentTimeMillis() { | |||
*/ | |||
boolean shouldAccept(Runnable runnable); | |||
} | |||
} | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert changes to this file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
return ((FutureRunnable) r).rescheduler.enabled; | ||
} | ||
|
||
private long nanoTime() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you did there. 😄
} | ||
} | ||
|
||
private static final class FutureRunnable implements Runnable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Why is this static?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In ManagedChannelImplIdlenessTest.java
there is a test that checks there are no more scheduled tasks in the scheduler. It fails because the tasks are still left over, but now disabled. I wanted to make it so the test scans the tasks and checks to see they are Rescheduler Runnables, and that they are disabled.
There needs to be a reference from the Runnable back to the Rescheduler, so this became static and took an explicit reference to the outer class. This is so isEnabled
below works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see. You could have added another method to FutureRunnable to do something like return Rescheduler.this
, but that's close to the same amount of effort. Makes sense.
assertFalse(runner.ran); | ||
rescheduler.reschedule(1, TimeUnit.NANOSECONDS); | ||
assertFalse(runner.ran); | ||
rescheduler.cancel(/* permanent= */ false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably need a test for cancel(true)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
rescheduler.reschedule(1, TimeUnit.NANOSECONDS); | ||
assertFalse(runner.ran); | ||
assertFalse(exec.executed); | ||
rescheduler.reschedule(50, TimeUnit.NANOSECONDS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you are keeping the flexibility of rescheduling with a shorter delay, you should cover it, or remove the flexibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@ejona86 @zhangkun83
I haven't quite got the tests to pass yet but I think this is close enough for review to take a look. The main idea is to avoid rescheduling the IdleModeTimer if it is already active. This has pretty good results on my machine for the latency benchmarks. With CPU freq scaling on, median latency goes from 197us to 185us. (no TLS, but with census enabled, direct executor).
The changes to get the tests to work are going to be harder since this change depends on
System.nanoTime
. TheFakeClock
we use in our tests doesn't make it easy to mock this out, so I'm working on ideas to fix this. That said, it is starting to get invasive for tests to pass.Raw numbers from my runs: