Sending interrupts to the worker threads upon teardown
Aleksey Shipilev
aleksey.shipilev at oracle.com
Mon Apr 14 17:27:45 UTC 2014
On 04/14/2014 09:01 PM, Aleksey Shipilev wrote:
> Hi Chris,
>
> On 04/14/2014 08:45 PM, Chris Vest wrote:
>> However, because of the blocking nature of the queue, there’s a
>> pretty high chance that the benchmark will get stuck, because the
>> shutdown of the producer does not exactly line up with the shutdown
>> of the consumer. The simplest way to fix this, that I can think of,
>> is to send them interrupts, since it is a common expectation of well
>> behaved blocking methods to respond to interrupts.
>
> Yeah, JMH today is not handing the interrupts well, though I agree
> interruptible benchmarks are the legitimate use case. We tried that
> before, but in the presence of complex @States with helper methods it
> was very prone to errors. We have an item on JMH TODO list to try that
> again in the near time.
And now I have second thoughts. There are basically two approaches to
handling the interrupts:
a) @GMB
public void testTake() throws InterruptedException {
// let the caller handle the exception
return q.take();
}
b) @GMB
public void testTake() {
try {
} catch (InterruptedException e) {
// ignore and exit the method, knowing we will never get back
}
}
Case (a) seems intuitively more pleasant, since it clearly communicates
the abrupt return to the harness. But there is little harness can do
with that info: say, in Mode.Throughput you are measuring the total time
and ops counted, it really matters where you put ops++:
Result measurementLoop(...) {
long ops = 0;
long time1 = System.nanoTime();
while(!isDone) {
try {
testTake();
// place the ops++ here?
} catch (InterruptedException e) {
break;
}
// or, place the ops++ here?
}
long time2 = System.nanoTime();
return new Result(ops, time2 - time1);
}
Both cases are wrong: putting ops++ in the try-catch block
underestimates ops (misses the short-circuited one), putting ops++ after
the try-catch block overestimates ops (includes short-circuited one in
the time measurement).
Moreover, considering that the interrupted return is probably for the
test method which had stuck, our timing measurement is already wrong. We
can allow this only in SampleTime, which samples the individual
execution times, but that seems too stifling.
Or, we can blindly deliver the interrupts knowing that people relying on
this have no reason to believe the performance numbers.
Thoughts?
-Aleksey.
P.S. While writing this up, it occurred to me that we can dodge the
entire interruption thing by specifying the order in which @GMB methods
in asymmetric benchmark should leave the measurement. In Chris' example
we should keep putter thread in measurement until taker leaves without
blocking. Hm... Maybe that makes Control redundant?
More information about the jmh-dev
mailing list