Skip to content

Commit 6073edf

Browse files
Eric CaspoleSergey Kuksenko
andcommitted
8307483: New micros for j.u.c.LockSupport
Co-authored-by: Sergey Kuksenko <skuksenko@openjdk.org> Reviewed-by: shade, redestad
1 parent 2409448 commit 6073edf

File tree

2 files changed

+273
-0
lines changed

2 files changed

+273
-0
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package org.openjdk.bench.java.util.concurrent;
24+
25+
import org.openjdk.jmh.annotations.Benchmark;
26+
import org.openjdk.jmh.annotations.BenchmarkMode;
27+
import org.openjdk.jmh.annotations.Fork;
28+
import org.openjdk.jmh.annotations.Measurement;
29+
import org.openjdk.jmh.annotations.Mode;
30+
import org.openjdk.jmh.annotations.OutputTimeUnit;
31+
import org.openjdk.jmh.annotations.Param;
32+
import org.openjdk.jmh.annotations.Scope;
33+
import org.openjdk.jmh.annotations.Setup;
34+
import org.openjdk.jmh.annotations.State;
35+
import org.openjdk.jmh.annotations.TearDown;
36+
import org.openjdk.jmh.annotations.Threads;
37+
import org.openjdk.jmh.annotations.Warmup;
38+
39+
import java.util.concurrent.BrokenBarrierException;
40+
import java.util.concurrent.CountDownLatch;
41+
import java.util.concurrent.CyclicBarrier;
42+
import java.util.concurrent.ExecutorService;
43+
import java.util.concurrent.Executors;
44+
import java.util.concurrent.TimeUnit;
45+
import java.util.concurrent.locks.LockSupport;
46+
47+
@BenchmarkMode(Mode.Throughput)
48+
@OutputTimeUnit(TimeUnit.SECONDS)
49+
@State(Scope.Benchmark)
50+
@Fork(1)
51+
@Threads(1)
52+
@Warmup(iterations = 5, time = 5)
53+
@Measurement(iterations = 5, time = 5)
54+
public class UnparkBenchSleepersAfter {
55+
56+
/*
57+
This micro creates thousands of sleeper threads after the threads doing the barrier await
58+
to see if that has any effect on the barrier performance.
59+
*/
60+
61+
@Param({"4000"})
62+
int idles;
63+
64+
@Param({"2"})
65+
int workers;
66+
67+
CyclicBarrier barrier;
68+
69+
@Benchmark
70+
public void barrier() throws InterruptedException {
71+
CountDownLatch latch = new CountDownLatch(workers);
72+
for (int i = 0; i < workers; i++) {
73+
exec.submit(() ->
74+
{
75+
try {
76+
barrier.await();
77+
} catch (InterruptedException | BrokenBarrierException e) {
78+
barrier.reset();
79+
} finally {
80+
latch.countDown();
81+
}
82+
});
83+
}
84+
latch.await();
85+
}
86+
87+
IdleRunnable[] idleRunnables;
88+
89+
ExecutorService exec;
90+
91+
@Setup
92+
public void setup() throws InterruptedException {
93+
barrier = new CyclicBarrier(workers);
94+
exec = Executors.newFixedThreadPool(workers);
95+
CountDownLatch latch = new CountDownLatch(workers);
96+
for (int i = 0; i < workers; i++) { // warmup exec
97+
exec.submit(() -> {
98+
try {
99+
Thread.sleep(0);
100+
} catch (InterruptedException e) {
101+
throw new RuntimeException(e);
102+
} finally {
103+
latch.countDown();
104+
}
105+
});
106+
}
107+
latch.await();
108+
idleRunnables = new IdleRunnable[idles];
109+
for(int i = 0; i < idles; i++) {
110+
IdleRunnable r = new IdleRunnable();
111+
idleRunnables[i] = r;
112+
new Thread(r).start();
113+
}
114+
}
115+
116+
@TearDown
117+
public void tearDown() {
118+
for (IdleRunnable r : idleRunnables) {
119+
r.stop();
120+
}
121+
exec.shutdown();
122+
}
123+
124+
public static class IdleRunnable implements Runnable {
125+
volatile boolean done;
126+
Thread myThread;
127+
128+
@Override
129+
public void run() {
130+
myThread = Thread.currentThread();
131+
while (!done) {
132+
LockSupport.park();
133+
}
134+
}
135+
136+
public void stop() {
137+
done = true;
138+
LockSupport.unpark(myThread);
139+
}
140+
}
141+
142+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package org.openjdk.bench.java.util.concurrent;
24+
25+
import org.openjdk.jmh.annotations.Benchmark;
26+
import org.openjdk.jmh.annotations.BenchmarkMode;
27+
import org.openjdk.jmh.annotations.Fork;
28+
import org.openjdk.jmh.annotations.Measurement;
29+
import org.openjdk.jmh.annotations.Mode;
30+
import org.openjdk.jmh.annotations.OutputTimeUnit;
31+
import org.openjdk.jmh.annotations.Param;
32+
import org.openjdk.jmh.annotations.Scope;
33+
import org.openjdk.jmh.annotations.Setup;
34+
import org.openjdk.jmh.annotations.State;
35+
import org.openjdk.jmh.annotations.TearDown;
36+
import org.openjdk.jmh.annotations.Threads;
37+
import org.openjdk.jmh.annotations.Warmup;
38+
import org.openjdk.jmh.infra.BenchmarkParams;
39+
import org.openjdk.jmh.infra.Control;
40+
41+
import java.util.concurrent.BrokenBarrierException;
42+
import java.util.concurrent.CountDownLatch;
43+
import java.util.concurrent.CyclicBarrier;
44+
import java.util.concurrent.Executor;
45+
import java.util.concurrent.ExecutorService;
46+
import java.util.concurrent.Executors;
47+
import java.util.concurrent.TimeUnit;
48+
import java.util.concurrent.atomic.LongAdder;
49+
import java.util.concurrent.locks.LockSupport;
50+
51+
@BenchmarkMode(Mode.Throughput)
52+
@OutputTimeUnit(TimeUnit.SECONDS)
53+
@State(Scope.Benchmark)
54+
@Fork(1)
55+
@Threads(1)
56+
@Warmup(iterations = 5, time = 5)
57+
@Measurement(iterations = 5, time = 5)
58+
public class UnparkBenchSleepersBefore {
59+
60+
/*
61+
This micro creates thousands of sleeper threads before the threads doing the barrier await
62+
to see if that has any effect on the barrier performance, as seen with JDK-8305670.
63+
*/
64+
65+
@Param({"4000"})
66+
int idles;
67+
68+
@Param({"2"})
69+
int workers;
70+
71+
CyclicBarrier barrier;
72+
73+
@Benchmark
74+
public void barrier() throws InterruptedException {
75+
CountDownLatch latch = new CountDownLatch(workers);
76+
for (int i = 0; i < workers; i++) {
77+
exec.submit(() -> {
78+
try {
79+
barrier.await();
80+
} catch (InterruptedException | BrokenBarrierException e) {
81+
barrier.reset();
82+
} finally {
83+
latch.countDown();
84+
}
85+
});
86+
}
87+
latch.await();
88+
}
89+
90+
IdleRunnable[] idleRunnables;
91+
92+
ExecutorService exec;
93+
94+
@Setup
95+
public void setup() {
96+
idleRunnables = new IdleRunnable[idles];
97+
for(int i = 0; i < idleRunnables.length; i++) {
98+
idleRunnables[i] = new IdleRunnable();
99+
new Thread(idleRunnables[i]).start();
100+
}
101+
barrier = new CyclicBarrier(workers);
102+
exec = Executors.newFixedThreadPool(workers); // order is important, create this executor only after idle threads
103+
}
104+
105+
@TearDown
106+
public void tearDown() {
107+
for (IdleRunnable r : idleRunnables) {
108+
r.stop();
109+
}
110+
exec.shutdown();
111+
}
112+
113+
public static class IdleRunnable implements Runnable {
114+
volatile boolean done;
115+
Thread myThread;
116+
117+
@Override
118+
public void run() {
119+
myThread = Thread.currentThread();
120+
while (!done) {
121+
LockSupport.park();
122+
}
123+
}
124+
125+
public void stop() {
126+
done = true;
127+
LockSupport.unpark(myThread);
128+
}
129+
}
130+
131+
}

0 commit comments

Comments
 (0)