Skip to content

Commit 4bd3c5b

Browse files
Use DependencyGraph in integration sorting
This updates the SmithyIntegration sorting to use the generic DependencyGraph. It also adds some benchmarking configurations, which show a minor speed bump for highly dependent integrations and a major speed bump for highly independent integrations.
1 parent e1c1c9e commit 4bd3c5b

File tree

4 files changed

+277
-78
lines changed

4 files changed

+277
-78
lines changed

smithy-codegen-core/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
plugins {
66
id("smithy.module-conventions")
7+
id("smithy.profiling-conventions")
78
}
89

910
description = "This module provides a code generation framework for generating clients, " +
@@ -14,6 +15,7 @@ extra["moduleName"] = "software.amazon.smithy.codegen.core"
1415

1516
dependencies {
1617
api(project(":smithy-utils"))
18+
jmh(project(":smithy-utils"))
1719
api(project(":smithy-model"))
1820
api(project(":smithy-build"))
1921
}
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,225 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
15
package software.amazon.smithy.codegen.core.jmh;
26

7+
import java.util.ArrayList;
8+
import java.util.Collections;
9+
import java.util.Comparator;
10+
import java.util.LinkedHashMap;
11+
import java.util.List;
12+
import java.util.Map;
13+
import java.util.concurrent.TimeUnit;
14+
import org.openjdk.jmh.annotations.Benchmark;
15+
import org.openjdk.jmh.annotations.BenchmarkMode;
16+
import org.openjdk.jmh.annotations.Fork;
17+
import org.openjdk.jmh.annotations.Measurement;
18+
import org.openjdk.jmh.annotations.Mode;
19+
import org.openjdk.jmh.annotations.Scope;
20+
import org.openjdk.jmh.annotations.Setup;
21+
import org.openjdk.jmh.annotations.State;
22+
import org.openjdk.jmh.annotations.Warmup;
23+
import software.amazon.smithy.codegen.core.CodegenContext;
24+
import software.amazon.smithy.codegen.core.ImportContainer;
25+
import software.amazon.smithy.codegen.core.SmithyIntegration;
26+
import software.amazon.smithy.codegen.core.Symbol;
27+
import software.amazon.smithy.codegen.core.SymbolWriter;
28+
29+
@Warmup(iterations = 3)
30+
@Measurement(iterations = 3, timeUnit = TimeUnit.MICROSECONDS)
31+
@BenchmarkMode(Mode.AverageTime)
32+
@Fork(1)
333
public class SmithyIntegrations {
34+
35+
@State(Scope.Thread)
36+
public static class SmithyIntegrationsState {
37+
public Map<String, SmithyIntegration<?, ?, ?>> independentIntegrations10;
38+
public Map<String, SmithyIntegration<?, ?, ?>> dependentIntegrations10;
39+
public Map<String, SmithyIntegration<?, ?, ?>> independentIntegrations100;
40+
public Map<String, SmithyIntegration<?, ?, ?>> dependentIntegrations100;
41+
public Map<String, SmithyIntegration<?, ?, ?>> independentIntegrations1000;
42+
public Map<String, SmithyIntegration<?, ?, ?>> dependentIntegrations1000;
43+
44+
@Setup
45+
public void setup() {
46+
independentIntegrations10 = new LinkedHashMap<>(10);
47+
independentIntegrations100 = new LinkedHashMap<>(100);
48+
independentIntegrations1000 = new LinkedHashMap<>(1000);
49+
for (int i = 0; i < 1000; i++) {
50+
String name = "integration" + i;
51+
TestIntegration integration = new TestIntegration(name);
52+
if (i < 10) {
53+
independentIntegrations10.put(name, integration);
54+
}
55+
if (i < 100) {
56+
independentIntegrations100.put(name, integration);
57+
}
58+
independentIntegrations1000.put(name, integration);
59+
}
60+
independentIntegrations100 = Collections.unmodifiableMap(independentIntegrations100);
61+
62+
dependentIntegrations10 = new LinkedHashMap<>(10);
63+
dependentIntegrations100 = new LinkedHashMap<>(100);
64+
dependentIntegrations1000 = new LinkedHashMap<>(1000);
65+
for (int i = 0; i < 1000; i++) {
66+
String name = "integration" + i;
67+
String next = "integration" + (i + 1);
68+
String afterNext = "integration" + (i + 2);
69+
70+
if (i < 10) {
71+
List<String> dependencies = new ArrayList<>();
72+
if (i < 9) {
73+
dependencies.add(next);
74+
}
75+
if (i < 8) {
76+
dependencies.add(afterNext);
77+
}
78+
dependentIntegrations10.put(name,
79+
new TestIntegration(name, (byte) 0, Collections.emptyList(), dependencies));
80+
}
81+
82+
if (i < 100) {
83+
List<String> dependencies = new ArrayList<>();
84+
if (i < 99) {
85+
dependencies.add(next);
86+
}
87+
if (i < 98) {
88+
dependencies.add(afterNext);
89+
}
90+
dependentIntegrations100.put(name,
91+
new TestIntegration(name, (byte) 0, Collections.emptyList(), dependencies));
92+
}
93+
94+
List<String> dependencies = new ArrayList<>();
95+
if (i < 999) {
96+
dependencies.add(next);
97+
}
98+
if (i < 998) {
99+
dependencies.add(afterNext);
100+
}
101+
dependentIntegrations1000.put(name,
102+
new TestIntegration(name, (byte) 0, Collections.emptyList(), dependencies));
103+
}
104+
}
105+
}
106+
107+
@Benchmark
108+
public List<SmithyIntegration<?, ?, ?>> sortIndependentIntegrations10(SmithyIntegrationsState state) {
109+
return SmithyIntegration.sort(state.independentIntegrations10.values());
110+
}
111+
112+
@Benchmark
113+
public List<SmithyIntegration<?, ?, ?>> sortIndependentIntegrations100(SmithyIntegrationsState state) {
114+
return SmithyIntegration.sort(state.independentIntegrations100.values());
115+
}
116+
117+
@Benchmark
118+
public List<SmithyIntegration<?, ?, ?>> sortIndependentIntegrations1000(SmithyIntegrationsState state) {
119+
return SmithyIntegration.sort(state.independentIntegrations1000.values());
120+
}
121+
122+
@Benchmark
123+
public List<SmithyIntegration<?, ?, ?>> sortDependentIntegrations10(SmithyIntegrationsState state) {
124+
return SmithyIntegration.sort(state.dependentIntegrations10.values());
125+
}
126+
127+
@Benchmark
128+
public List<SmithyIntegration<?, ?, ?>> sortDependentIntegrations100(SmithyIntegrationsState state) {
129+
return SmithyIntegration.sort(state.dependentIntegrations100.values());
130+
}
131+
132+
@Benchmark
133+
public List<SmithyIntegration<?, ?, ?>> sortDependentIntegrations1000(SmithyIntegrationsState state) {
134+
return SmithyIntegration.sort(state.dependentIntegrations1000.values());
135+
}
136+
137+
private static class IntegrationComparator implements Comparator<String> {
138+
139+
private final Map<String, SmithyIntegration<?, ?, ?>> lookup;
140+
141+
IntegrationComparator(Map<String, SmithyIntegration<?, ?, ?>> lookup) {
142+
this.lookup = lookup;
143+
}
144+
145+
@Override
146+
public int compare(String o1, String o2) {
147+
SmithyIntegration<?, ?, ?> left = lookup.get(o1);
148+
SmithyIntegration<?, ?, ?> right = lookup.get(o2);
149+
if (left == null || right == null) {
150+
return 0;
151+
}
152+
return Byte.compare(left.priority(), right.priority());
153+
}
154+
}
155+
156+
private static class TestImportContainer implements ImportContainer {
157+
@Override
158+
public void importSymbol(Symbol symbol, String alias) {
159+
160+
}
161+
}
162+
163+
private static class TestSymbolWriter extends SymbolWriter<TestSymbolWriter, TestImportContainer> {
164+
public TestSymbolWriter(TestImportContainer importContainer) {
165+
super(importContainer);
166+
}
167+
}
168+
169+
private static class TestSettings {}
170+
171+
private static class TestIntegration implements SmithyIntegration<
172+
TestSettings,
173+
TestSymbolWriter,
174+
CodegenContext<TestSettings, TestSymbolWriter, TestIntegration>> {
175+
176+
private final String name;
177+
private final byte priority;
178+
private final List<String> runBefore;
179+
private final List<String> runAfter;
180+
181+
TestIntegration(String name) {
182+
this(name, (byte) 0);
183+
}
184+
185+
TestIntegration(String name, byte priority) {
186+
this(name, priority, Collections.emptyList());
187+
}
188+
189+
TestIntegration(String name, byte priority, List<String> runBefore) {
190+
this(name, priority, runBefore, Collections.emptyList());
191+
}
192+
193+
TestIntegration(String name, byte priority, List<String> runBefore, List<String> runAfter) {
194+
this.name = name;
195+
this.priority = priority;
196+
this.runBefore = runBefore;
197+
this.runAfter = runAfter;
198+
}
199+
200+
@Override
201+
public String name() {
202+
return name;
203+
}
204+
205+
@Override
206+
public byte priority() {
207+
return priority;
208+
}
209+
210+
@Override
211+
public List<String> runBefore() {
212+
return runBefore;
213+
}
214+
215+
@Override
216+
public List<String> runAfter() {
217+
return runAfter;
218+
}
219+
220+
@Override
221+
public String toString() {
222+
return name();
223+
}
224+
}
4225
}

0 commit comments

Comments
 (0)