Skip to content

Commit 99f5ece

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 aa6cbec commit 99f5ece

File tree

5 files changed

+292
-86
lines changed

5 files changed

+292
-86
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{
22
"type": "feature",
33
"description": "Add a generic dependency graph to smithy-utils to be used for sorting various dependent objects, such as integrations and plugins.",
4-
"pull_requests": []
4+
"pull_requests": [
5+
"[#2774](https://github.com/smithy-lang/smithy/pull/2774)"
6+
]
57
}

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: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,230 @@
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+
independentIntegrations10 = Collections.unmodifiableMap(independentIntegrations10);
61+
independentIntegrations100 = Collections.unmodifiableMap(independentIntegrations100);
62+
independentIntegrations1000 = Collections.unmodifiableMap(independentIntegrations1000);
63+
64+
dependentIntegrations10 = new LinkedHashMap<>(10);
65+
dependentIntegrations100 = new LinkedHashMap<>(100);
66+
dependentIntegrations1000 = new LinkedHashMap<>(1000);
67+
for (int i = 0; i < 1000; i++) {
68+
String name = "integration" + i;
69+
String next = "integration" + (i + 1);
70+
String afterNext = "integration" + (i + 2);
71+
72+
if (i < 10) {
73+
List<String> dependencies = new ArrayList<>();
74+
if (i < 9) {
75+
dependencies.add(next);
76+
}
77+
if (i < 8) {
78+
dependencies.add(afterNext);
79+
}
80+
dependentIntegrations10.put(name,
81+
new TestIntegration(name, (byte) 0, Collections.emptyList(), dependencies));
82+
}
83+
84+
if (i < 100) {
85+
List<String> dependencies = new ArrayList<>();
86+
if (i < 99) {
87+
dependencies.add(next);
88+
}
89+
if (i < 98) {
90+
dependencies.add(afterNext);
91+
}
92+
dependentIntegrations100.put(name,
93+
new TestIntegration(name, (byte) 0, Collections.emptyList(), dependencies));
94+
}
95+
96+
List<String> dependencies = new ArrayList<>();
97+
if (i < 999) {
98+
dependencies.add(next);
99+
}
100+
if (i < 998) {
101+
dependencies.add(afterNext);
102+
}
103+
dependentIntegrations1000.put(name,
104+
new TestIntegration(name, (byte) 0, Collections.emptyList(), dependencies));
105+
}
106+
dependentIntegrations10 = Collections.unmodifiableMap(dependentIntegrations10);
107+
dependentIntegrations100 = Collections.unmodifiableMap(dependentIntegrations100);
108+
dependentIntegrations1000 = Collections.unmodifiableMap(dependentIntegrations1000);
109+
}
110+
}
111+
112+
@Benchmark
113+
public List<SmithyIntegration<?, ?, ?>> sortIndependentIntegrations10(SmithyIntegrationsState state) {
114+
return SmithyIntegration.sort(state.independentIntegrations10.values());
115+
}
116+
117+
@Benchmark
118+
public List<SmithyIntegration<?, ?, ?>> sortIndependentIntegrations100(SmithyIntegrationsState state) {
119+
return SmithyIntegration.sort(state.independentIntegrations100.values());
120+
}
121+
122+
@Benchmark
123+
public List<SmithyIntegration<?, ?, ?>> sortIndependentIntegrations1000(SmithyIntegrationsState state) {
124+
return SmithyIntegration.sort(state.independentIntegrations1000.values());
125+
}
126+
127+
@Benchmark
128+
public List<SmithyIntegration<?, ?, ?>> sortDependentIntegrations10(SmithyIntegrationsState state) {
129+
return SmithyIntegration.sort(state.dependentIntegrations10.values());
130+
}
131+
132+
@Benchmark
133+
public List<SmithyIntegration<?, ?, ?>> sortDependentIntegrations100(SmithyIntegrationsState state) {
134+
return SmithyIntegration.sort(state.dependentIntegrations100.values());
135+
}
136+
137+
@Benchmark
138+
public List<SmithyIntegration<?, ?, ?>> sortDependentIntegrations1000(SmithyIntegrationsState state) {
139+
return SmithyIntegration.sort(state.dependentIntegrations1000.values());
140+
}
141+
142+
private static class IntegrationComparator implements Comparator<String> {
143+
144+
private final Map<String, SmithyIntegration<?, ?, ?>> lookup;
145+
146+
IntegrationComparator(Map<String, SmithyIntegration<?, ?, ?>> lookup) {
147+
this.lookup = lookup;
148+
}
149+
150+
@Override
151+
public int compare(String o1, String o2) {
152+
SmithyIntegration<?, ?, ?> left = lookup.get(o1);
153+
SmithyIntegration<?, ?, ?> right = lookup.get(o2);
154+
if (left == null || right == null) {
155+
return 0;
156+
}
157+
return Byte.compare(left.priority(), right.priority());
158+
}
159+
}
160+
161+
private static class TestImportContainer implements ImportContainer {
162+
@Override
163+
public void importSymbol(Symbol symbol, String alias) {
164+
165+
}
166+
}
167+
168+
private static class TestSymbolWriter extends SymbolWriter<TestSymbolWriter, TestImportContainer> {
169+
public TestSymbolWriter(TestImportContainer importContainer) {
170+
super(importContainer);
171+
}
172+
}
173+
174+
private static class TestSettings {}
175+
176+
private static class TestIntegration implements SmithyIntegration<
177+
TestSettings,
178+
TestSymbolWriter,
179+
CodegenContext<TestSettings, TestSymbolWriter, TestIntegration>> {
180+
181+
private final String name;
182+
private final byte priority;
183+
private final List<String> runBefore;
184+
private final List<String> runAfter;
185+
186+
TestIntegration(String name) {
187+
this(name, (byte) 0);
188+
}
189+
190+
TestIntegration(String name, byte priority) {
191+
this(name, priority, Collections.emptyList());
192+
}
193+
194+
TestIntegration(String name, byte priority, List<String> runBefore) {
195+
this(name, priority, runBefore, Collections.emptyList());
196+
}
197+
198+
TestIntegration(String name, byte priority, List<String> runBefore, List<String> runAfter) {
199+
this.name = name;
200+
this.priority = priority;
201+
this.runBefore = runBefore;
202+
this.runAfter = runAfter;
203+
}
204+
205+
@Override
206+
public String name() {
207+
return name;
208+
}
209+
210+
@Override
211+
public byte priority() {
212+
return priority;
213+
}
214+
215+
@Override
216+
public List<String> runBefore() {
217+
return runBefore;
218+
}
219+
220+
@Override
221+
public List<String> runAfter() {
222+
return runAfter;
223+
}
224+
225+
@Override
226+
public String toString() {
227+
return name();
228+
}
229+
}
4230
}

0 commit comments

Comments
 (0)