Skip to content

Commit 152167e

Browse files
akarnokdakarnokd
akarnokd
authored and
akarnokd
committed
Added perf tests for various container-like subscriptions
1 parent 0d155ae commit 152167e

File tree

7 files changed

+739
-2
lines changed

7 files changed

+739
-2
lines changed

src/main/java/rx/internal/util/SubscriptionList.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,17 @@ public void add(final Subscription s) {
7878
*/
7979
@Override
8080
public void unsubscribe() {
81+
List<Subscription> list;
8182
synchronized (this) {
8283
if (unsubscribed) {
8384
return;
8485
}
8586
unsubscribed = true;
87+
list = subscriptions;
88+
subscriptions = null;
8689
}
8790
// we will only get here once
88-
unsubscribeFromAll(subscriptions);
89-
subscriptions = null;
91+
unsubscribeFromAll(list);
9092
}
9193

9294
private static void unsubscribeFromAll(Collection<Subscription> subscriptions) {
@@ -119,4 +121,13 @@ private static void unsubscribeFromAll(Collection<Subscription> subscriptions) {
119121
}
120122
}
121123
}
124+
/* perf support */
125+
public void clear() {
126+
List<Subscription> list;
127+
synchronized (this) {
128+
list = subscriptions;
129+
subscriptions = null;
130+
}
131+
unsubscribeFromAll(list);
132+
}
122133
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package rx.subscriptions;
18+
19+
import java.util.concurrent.TimeUnit;
20+
21+
import org.openjdk.jmh.annotations.Benchmark;
22+
import org.openjdk.jmh.annotations.BenchmarkMode;
23+
import org.openjdk.jmh.annotations.Group;
24+
import org.openjdk.jmh.annotations.GroupThreads;
25+
import org.openjdk.jmh.annotations.Mode;
26+
import org.openjdk.jmh.annotations.OutputTimeUnit;
27+
import org.openjdk.jmh.annotations.Param;
28+
import org.openjdk.jmh.annotations.Scope;
29+
import org.openjdk.jmh.annotations.Setup;
30+
import org.openjdk.jmh.annotations.State;
31+
import org.openjdk.jmh.annotations.Threads;
32+
33+
import rx.Subscription;
34+
35+
/**
36+
* Benchmark typical composite subscription concurrent behavior.
37+
* <p>
38+
* gradlew benchmarks "-Pjmh=-f 1 -tu s -bm thrpt -wi 5 -i 5 -r 1 .*CompositeSubscriptionConcurrentPerf.*"
39+
* <p>
40+
* gradlew benchmarks "-Pjmh=-f 1 -tu ns -bm avgt -wi 5 -i 5 -r 1 .*CompositeSubscriptionConcurrentPerf.*"
41+
*/
42+
@BenchmarkMode(Mode.Throughput)
43+
@OutputTimeUnit(TimeUnit.SECONDS)
44+
@Threads(2)
45+
@State(Scope.Group)
46+
public class CompositeSubscriptionConcurrentPerf {
47+
@Param({ "1", "1000", "100000" })
48+
public int loop;
49+
50+
public final CompositeSubscription csub = new CompositeSubscription();
51+
@Param({ "1", "5", "10", "20" })
52+
public int count;
53+
54+
public Subscription[] values;
55+
@Setup
56+
public void setup() {
57+
values = new Subscription[count * 2];
58+
for (int i = 0; i < count * 2; i++) {
59+
values[i] = new Subscription() {
60+
@Override
61+
public boolean isUnsubscribed() {
62+
return false;
63+
}
64+
@Override
65+
public void unsubscribe() {
66+
67+
}
68+
};
69+
}
70+
}
71+
72+
@Group("g1")
73+
@GroupThreads(1)
74+
@Benchmark
75+
public void addRemoveT1() {
76+
CompositeSubscription csub = this.csub;
77+
Subscription[] values = this.values;
78+
79+
for (int i = loop; i > 0; i--) {
80+
for (int j = values.length - 1; j >= 0; j--) {
81+
csub.add(values[j]);
82+
}
83+
for (int j = values.length - 1; j >= 0; j--) {
84+
csub.remove(values[j]);
85+
}
86+
}
87+
}
88+
@Group("g1")
89+
@GroupThreads(1)
90+
@Benchmark
91+
public void addRemoveT2() {
92+
CompositeSubscription csub = this.csub;
93+
Subscription[] values = this.values;
94+
95+
for (int i = loop; i > 0; i--) {
96+
for (int j = values.length - 1; j >= 0; j--) {
97+
csub.add(values[j]);
98+
}
99+
for (int j = values.length - 1; j >= 0; j--) {
100+
csub.remove(values[j]);
101+
}
102+
}
103+
}
104+
@Group("g2")
105+
@GroupThreads(1)
106+
@Benchmark
107+
public void addRemoveHalfT1() {
108+
CompositeSubscription csub = this.csub;
109+
Subscription[] values = this.values;
110+
int n = values.length;
111+
112+
for (int i = loop; i > 0; i--) {
113+
for (int j = n / 2 - 1; j >= 0; j--) {
114+
csub.add(values[j]);
115+
}
116+
for (int j = n / 2 - 1; j >= 0; j--) {
117+
csub.remove(values[j]);
118+
}
119+
}
120+
}
121+
@Group("g2")
122+
@GroupThreads(1)
123+
@Benchmark
124+
public void addRemoveHalfT2() {
125+
CompositeSubscription csub = this.csub;
126+
Subscription[] values = this.values;
127+
int n = values.length;
128+
129+
for (int i = loop; i > 0; i--) {
130+
for (int j = n - 1; j >= n / 2; j--) {
131+
csub.add(values[j]);
132+
}
133+
for (int j = n - 1; j >= n / 2; j--) {
134+
csub.remove(values[j]);
135+
}
136+
}
137+
}
138+
@Group("g3")
139+
@GroupThreads(1)
140+
@Benchmark
141+
public void addClearT1() {
142+
CompositeSubscription csub = this.csub;
143+
Subscription[] values = this.values;
144+
145+
for (int i = loop; i > 0; i--) {
146+
for (int j = values.length - 1; j >= 0; j--) {
147+
csub.add(values[j]);
148+
}
149+
csub.clear();
150+
}
151+
}
152+
@Group("g3")
153+
@GroupThreads(1)
154+
@Benchmark
155+
public void addClearT2() {
156+
CompositeSubscription csub = this.csub;
157+
Subscription[] values = this.values;
158+
159+
for (int i = loop; i > 0; i--) {
160+
for (int j = values.length - 1; j >= 0; j--) {
161+
csub.add(values[j]);
162+
}
163+
for (int j = values.length - 1; j >= 0; j--) {
164+
csub.remove(values[j]);
165+
}
166+
}
167+
}
168+
@Group("g4")
169+
@GroupThreads(1)
170+
@Benchmark
171+
public void addClearHalfT1() {
172+
CompositeSubscription csub = this.csub;
173+
Subscription[] values = this.values;
174+
int n = values.length;
175+
176+
for (int i = loop; i > 0; i--) {
177+
for (int j = n / 2 - 1; j >= 0; j--) {
178+
csub.add(values[j]);
179+
}
180+
csub.clear();
181+
}
182+
}
183+
@Group("g4")
184+
@GroupThreads(1)
185+
@Benchmark
186+
public void addClearHalfT2() {
187+
CompositeSubscription csub = this.csub;
188+
Subscription[] values = this.values;
189+
int n = values.length;
190+
191+
for (int i = loop; i > 0; i--) {
192+
for (int j = n - 1; j >= n / 2; j--) {
193+
csub.add(values[j]);
194+
}
195+
csub.clear();
196+
}
197+
}
198+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* Copyright 2014 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package rx.subscriptions;
18+
19+
import java.util.concurrent.TimeUnit;
20+
21+
import org.openjdk.jmh.annotations.Benchmark;
22+
import org.openjdk.jmh.annotations.BenchmarkMode;
23+
import org.openjdk.jmh.annotations.Mode;
24+
import org.openjdk.jmh.annotations.OutputTimeUnit;
25+
import org.openjdk.jmh.annotations.Param;
26+
import org.openjdk.jmh.annotations.Scope;
27+
import org.openjdk.jmh.annotations.Setup;
28+
import org.openjdk.jmh.annotations.State;
29+
30+
import rx.Subscription;
31+
32+
/**
33+
* Benchmark typical composite subscription single-threaded behavior.
34+
* <p>
35+
* gradlew benchmarks "-Pjmh=-f 1 -tu s -bm thrpt -wi 5 -i 5 -r 1 .*CompositeSubscriptionPerf.*"
36+
* <p>
37+
* gradlew benchmarks "-Pjmh=-f 1 -tu ns -bm avgt -wi 5 -i 5 -r 1 .*CompositeSubscriptionPerf.*"
38+
*/
39+
@BenchmarkMode(Mode.Throughput)
40+
@OutputTimeUnit(TimeUnit.SECONDS)
41+
public class CompositeSubscriptionPerf {
42+
@State(Scope.Thread)
43+
public static class TheState {
44+
@Param({ "1", "1000", "100000" })
45+
public int loop;
46+
@Param({ "1", "5", "10", "100" })
47+
public int count;
48+
49+
public final CompositeSubscription csub = new CompositeSubscription();
50+
51+
public Subscription[] values;
52+
@Setup
53+
public void setup() {
54+
values = new Subscription[count];
55+
for (int i = 0; i < count; i++) {
56+
values[i] = new Subscription() {
57+
@Override
58+
public boolean isUnsubscribed() {
59+
return false;
60+
}
61+
@Override
62+
public void unsubscribe() {
63+
64+
}
65+
};
66+
}
67+
}
68+
}
69+
@Benchmark
70+
public void addRemove(TheState state) {
71+
CompositeSubscription csub = state.csub;
72+
Subscription[] values = state.values;
73+
74+
for (int i = state.loop; i > 0; i--) {
75+
for (int j = values.length - 1; j >= 0; j--) {
76+
csub.add(state.values[j]);
77+
}
78+
for (int j = values.length - 1; j >= 0; j--) {
79+
csub.remove(state.values[j]);
80+
}
81+
}
82+
}
83+
@Benchmark
84+
public void addRemoveLocal(TheState state) {
85+
CompositeSubscription csub = new CompositeSubscription();
86+
Subscription[] values = state.values;
87+
88+
for (int i = state.loop; i > 0; i--) {
89+
for (int j = values.length - 1; j >= 0; j--) {
90+
csub.add(state.values[j]);
91+
}
92+
for (int j = values.length - 1; j >= 0; j--) {
93+
csub.remove(state.values[j]);
94+
}
95+
}
96+
}
97+
@Benchmark
98+
public void addClear(TheState state) {
99+
CompositeSubscription csub = state.csub;
100+
Subscription[] values = state.values;
101+
102+
for (int i = state.loop; i > 0; i--) {
103+
for (int j = values.length - 1; j >= 0; j--) {
104+
csub.add(state.values[j]);
105+
}
106+
csub.clear();
107+
}
108+
}
109+
@Benchmark
110+
public void addClearLocal(TheState state) {
111+
CompositeSubscription csub = new CompositeSubscription();
112+
Subscription[] values = state.values;
113+
114+
for (int i = state.loop; i > 0; i--) {
115+
for (int j = values.length - 1; j >= 0; j--) {
116+
csub.add(state.values[j]);
117+
}
118+
csub.clear();
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)