Skip to content

Commit 0f41463

Browse files
authored
Merge pull request #429 from IBM/issue-424
Issue 424 - fhir-model perf tweaks and benchmarking
2 parents b399ae0 + b3cdcf9 commit 0f41463

271 files changed

Lines changed: 109903 additions & 3950 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

fhir-benchmark/pom.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
<name>FHIR Benchmark</name>
1212

1313
<dependencies>
14+
<!-- <dependency>
15+
<groupId>com.sample</groupId>
16+
<artifactId>sample</artifactId>
17+
<version>1.0</version>
18+
<scope>system</scope>
19+
<systemPath>${project.basedir}/src/main/resources/files.jar</systemPath>
20+
</dependency> -->
1421
<dependency>
1522
<groupId>org.openjdk.jmh</groupId>
1623
<artifactId>jmh-core</artifactId>
@@ -133,6 +140,15 @@
133140
<target>${javac.target}</target>
134141
</configuration>
135142
</plugin>
143+
<plugin>
144+
<groupId>org.apache.maven.plugins</groupId>
145+
<artifactId>maven-jar-plugin</artifactId>
146+
<configuration>
147+
<archive>
148+
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
149+
</archive>
150+
</configuration>
151+
</plugin>
136152
<plugin>
137153
<groupId>org.apache.maven.plugins</groupId>
138154
<artifactId>maven-shade-plugin</artifactId>

fhir-benchmark/src/main/java/com/ibm/fhir/benchmark/FHIRGeneratorBenchmark.java

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66

77
package com.ibm.fhir.benchmark;
88

9-
import static com.ibm.fhir.benchmark.runner.FHIRBenchmarkRunner.PROPERTY_EXAMPLE_NAME;
10-
119
import java.io.StringReader;
1210
import java.io.Writer;
1311

1412
import org.hl7.fhir.instance.model.api.IBaseResource;
1513
import org.openjdk.jmh.annotations.Benchmark;
14+
import org.openjdk.jmh.annotations.Param;
1615
import org.openjdk.jmh.annotations.Scope;
1716
import org.openjdk.jmh.annotations.Setup;
1817
import org.openjdk.jmh.annotations.State;
@@ -27,52 +26,63 @@
2726
import ca.uhn.fhir.context.FhirContext;
2827

2928
public class FHIRGeneratorBenchmark {
29+
static final Writer NOP_WRITER = BenchmarkUtil.createNOPWriter();
30+
31+
@State(Scope.Thread)
32+
public static class FHIRGenerators {
33+
FHIRGenerator jsonGenerator = FHIRGenerator.generator(Format.JSON);
34+
FHIRGenerator xmlGenerator = FHIRGenerator.generator(Format.XML);
35+
}
36+
3037
@State(Scope.Benchmark)
3138
public static class FHIRGeneratorState {
32-
public static final Writer NOP_WRITER = BenchmarkUtil.createNOPWriter();
33-
public static final String SPEC_EXAMPLE_NAME = System.getProperty(PROPERTY_EXAMPLE_NAME);
34-
public static final String JSON_SPEC_EXAMPLE = BenchmarkUtil.getSpecExample(Format.JSON, SPEC_EXAMPLE_NAME);
35-
public static final String XML_SPEC_EXAMPLE = BenchmarkUtil.getSpecExample(Format.XML, SPEC_EXAMPLE_NAME);
39+
FhirContext context;
40+
Resource resource;
41+
IBaseResource baseResource;
3642

37-
public FhirContext context;
38-
public FHIRGenerator jsonGenerator;
39-
public FHIRGenerator xmlGenerator;
40-
public Resource resource;
41-
public IBaseResource baseResource;
43+
// JMH will inject the value into the annotated field before any Setup method is called.
44+
@Param({"valuesets"})
45+
public String exampleName;
4246

4347
@Setup
44-
public void setUp() throws Exception {
45-
context = FhirContext.forR4();
46-
jsonGenerator = FHIRGenerator.generator(Format.JSON);
47-
xmlGenerator = FHIRGenerator.generator(Format.XML);
48+
public void setUp() throws Exception {
49+
if (exampleName == null) {
50+
System.err.println("exampleName is null; if you're in Eclipse then make sure annotation processing is on and you've ran 'mvn clean package'.");
51+
System.exit(1);
52+
}
53+
54+
// us
55+
String JSON_SPEC_EXAMPLE = BenchmarkUtil.getSpecExample(Format.JSON, exampleName);
4856
resource = FHIRParser.parser(Format.JSON).parse(new StringReader(JSON_SPEC_EXAMPLE));
57+
58+
// HAPI
59+
context = FhirContext.forR4();
4960
baseResource = context.newJsonParser().parseResource(new StringReader(JSON_SPEC_EXAMPLE));
5061
}
5162
}
5263

5364
@Benchmark
54-
public void benchmarkJsonGenerator(FHIRGeneratorState state) throws Exception {
55-
state.jsonGenerator.generate(state.resource, FHIRGeneratorState.NOP_WRITER);
65+
public void benchmarkJsonGenerator(FHIRGenerators generators, FHIRGeneratorState state) throws Exception {
66+
generators.jsonGenerator.generate(state.resource, NOP_WRITER);
5667
}
5768

5869
@Benchmark
59-
public void benchmarkXMLGenerator(FHIRGeneratorState state) throws Exception {
60-
state.xmlGenerator.generate(state.resource, FHIRGeneratorState.NOP_WRITER);
70+
public void benchmarkXMLGenerator(FHIRGenerators generators, FHIRGeneratorState state) throws Exception {
71+
generators.xmlGenerator.generate(state.resource, NOP_WRITER);
6172
}
6273

6374
@Benchmark
6475
public void benchmarkHAPIJsonGenerator(FHIRGeneratorState state) throws Exception {
65-
state.context.newJsonParser().encodeResourceToWriter(state.baseResource, FHIRGeneratorState.NOP_WRITER);
76+
state.context.newJsonParser().encodeResourceToWriter(state.baseResource, NOP_WRITER);
6677
}
6778

6879
@Benchmark
6980
public void benchmarkHAPIXMLGenerator(FHIRGeneratorState state) throws Exception {
70-
state.context.newXmlParser().encodeResourceToWriter(state.baseResource, FHIRGeneratorState.NOP_WRITER);
81+
state.context.newXmlParser().encodeResourceToWriter(state.baseResource, NOP_WRITER);
7182
}
7283

7384
public static void main(String[] args) throws Exception {
7485
new FHIRBenchmarkRunner(FHIRGeneratorBenchmark.class)
75-
.property(PROPERTY_EXAMPLE_NAME, BenchmarkUtil.getRandomSpecExampleName())
76-
.run();
86+
.run(BenchmarkUtil.getRandomSpecExampleName());
7787
}
7888
}

fhir-benchmark/src/main/java/com/ibm/fhir/benchmark/FHIRParserBenchmark.java

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66

77
package com.ibm.fhir.benchmark;
88

9-
import static com.ibm.fhir.benchmark.runner.FHIRBenchmarkRunner.PROPERTY_EXAMPLE_NAME;
10-
9+
import java.io.IOException;
1110
import java.io.StringReader;
12-
import java.io.Writer;
1311

1412
import org.openjdk.jmh.annotations.Benchmark;
13+
import org.openjdk.jmh.annotations.Param;
1514
import org.openjdk.jmh.annotations.Scope;
1615
import org.openjdk.jmh.annotations.Setup;
1716
import org.openjdk.jmh.annotations.State;
@@ -20,54 +19,65 @@
2019
import com.ibm.fhir.benchmark.util.BenchmarkUtil;
2120
import com.ibm.fhir.model.format.Format;
2221
import com.ibm.fhir.model.parser.FHIRParser;
22+
import com.ibm.fhir.model.resource.Resource;
2323

2424
import ca.uhn.fhir.context.FhirContext;
2525
import ca.uhn.fhir.parser.StrictErrorHandler;
2626

27+
2728
public class FHIRParserBenchmark {
29+
@State(Scope.Thread)
30+
public static class FHIRParsers {
31+
FHIRParser jsonParser = FHIRParser.parser(Format.JSON);
32+
FHIRParser xmlParser = FHIRParser.parser(Format.XML);
33+
}
34+
2835
@State(Scope.Benchmark)
2936
public static class FHIRParserState {
30-
public static final Writer NOP_WRITER = BenchmarkUtil.createNOPWriter();
31-
public static final String SPEC_EXAMPLE_NAME = System.getProperty(PROPERTY_EXAMPLE_NAME);
32-
public static final String JSON_SPEC_EXAMPLE = BenchmarkUtil.getSpecExample(Format.JSON, SPEC_EXAMPLE_NAME);
33-
public static final String XML_SPEC_EXAMPLE = BenchmarkUtil.getSpecExample(Format.XML, SPEC_EXAMPLE_NAME);
37+
FhirContext context;
38+
String JSON_SPEC_EXAMPLE;
39+
String XML_SPEC_EXAMPLE;
3440

35-
public FhirContext context;
36-
public FHIRParser jsonParser;
37-
public FHIRParser xmlParser;
41+
// JMH will inject the value into the annotated field before any Setup method is called.
42+
@Param({"valuesets"})
43+
public String exampleName;
3844

3945
@Setup
40-
public void setUp() {
46+
public void setUp() throws IOException {
47+
if (exampleName == null) {
48+
System.err.println("exampleName is null; if you're in Eclipse then make sure annotation processing is on and you've ran 'mvn clean package'.");
49+
System.exit(1);
50+
}
51+
System.out.println("Setting up for example " + exampleName);
4152
context = FhirContext.forR4();
4253
context.setParserErrorHandler(new StrictErrorHandler());
43-
jsonParser = FHIRParser.parser(Format.JSON);
44-
xmlParser = FHIRParser.parser(Format.XML);
54+
JSON_SPEC_EXAMPLE = BenchmarkUtil.getSpecExample(Format.JSON, exampleName);
55+
XML_SPEC_EXAMPLE = BenchmarkUtil.getSpecExample(Format.XML, exampleName);
4556
}
4657
}
4758

4859
@Benchmark
49-
public void benchmarkJsonParser(FHIRParserState state) throws Exception {
50-
state.jsonParser.parse(new StringReader(FHIRParserState.JSON_SPEC_EXAMPLE));
60+
public Resource benchmarkJsonParser(FHIRParsers parsers, FHIRParserState state) throws Exception {
61+
return parsers.jsonParser.parse(new StringReader(state.JSON_SPEC_EXAMPLE));
5162
}
5263

5364
@Benchmark
54-
public void benchmarkXMLParser(FHIRParserState state) throws Exception {
55-
state.xmlParser.parse(new StringReader(FHIRParserState.XML_SPEC_EXAMPLE));
65+
public Resource benchmarkXMLParser(FHIRParsers parsers, FHIRParserState state) throws Exception {
66+
return parsers.xmlParser.parse(new StringReader(state.XML_SPEC_EXAMPLE));
5667
}
5768

5869
@Benchmark
5970
public void benchmarkHAPIJsonParser(FHIRParserState state) throws Exception {
60-
state.context.newJsonParser().parseResource(new StringReader(FHIRParserState.JSON_SPEC_EXAMPLE));
71+
state.context.newJsonParser().parseResource(new StringReader(state.JSON_SPEC_EXAMPLE));
6172
}
6273

6374
@Benchmark
6475
public void benchmarkHAPIXMLParser(FHIRParserState state) throws Exception {
65-
state.context.newXmlParser().parseResource(new StringReader(FHIRParserState.XML_SPEC_EXAMPLE));
76+
state.context.newXmlParser().parseResource(new StringReader(state.XML_SPEC_EXAMPLE));
6677
}
6778

6879
public static void main(String[] args) throws Exception {
69-
new FHIRBenchmarkRunner(FHIRParserBenchmark.class)
70-
.property(PROPERTY_EXAMPLE_NAME, BenchmarkUtil.getRandomSpecExampleName())
71-
.run();
80+
// new FHIRBenchmarkRunner(FHIRParserBenchmark.class).runAll();
81+
new FHIRBenchmarkRunner(FHIRParserBenchmark.class).run();
7282
}
7383
}

fhir-benchmark/src/main/java/com/ibm/fhir/benchmark/FHIRParserValidatorGeneratorBenchmark.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ public void benchmarkHAPIXMLParserValidatorGenerator(FHIRParserValidatorGenerato
9191

9292
public static void main(String[] args) throws Exception {
9393
new FHIRBenchmarkRunner(FHIRParserValidatorGeneratorBenchmark.class)
94-
.property(PROPERTY_EXAMPLE_NAME, BenchmarkUtil.getRandomSpecExampleName())
9594
.run();
9695
}
9796
}

fhir-benchmark/src/main/java/com/ibm/fhir/benchmark/FHIRPathEvaluatorBenchmark.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,6 @@ public static void main(String[] args) throws Exception {
9191
new FHIRBenchmarkRunner(FHIRPathEvaluatorBenchmark.class)
9292
.property(PROPERTY_EXAMPLE_NAME, EXAMPLE_NAME)
9393
.property(PROPERTY_EXPRESSION, EXPRESSION)
94-
.run();
94+
.run(BenchmarkUtil.getRandomSpecExampleName());
9595
}
9696
}

fhir-benchmark/src/main/java/com/ibm/fhir/benchmark/FHIRValidatorBenchmark.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public void benchmarkHAPIValidator(FHIRValidatorState state) throws Exception {
6363

6464
public static void main(String[] args) throws Exception {
6565
new FHIRBenchmarkRunner(FHIRValidatorBenchmark.class)
66-
.property(PROPERTY_EXAMPLE_NAME, BenchmarkUtil.getRandomSpecExampleName())
67-
.run();
66+
.run(BenchmarkUtil.getRandomSpecExampleName());
6867
}
6968
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* (C) Copyright IBM Corp. 2019
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package com.ibm.fhir.benchmark;
8+
9+
import java.io.BufferedReader;
10+
import java.io.InputStream;
11+
import java.io.InputStreamReader;
12+
import java.io.ObjectInputStream;
13+
import java.io.Reader;
14+
import java.util.HashSet;
15+
import java.util.List;
16+
import java.util.Set;
17+
18+
import org.openjdk.jmh.annotations.Benchmark;
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.runner.Runner;
23+
import org.openjdk.jmh.runner.options.Options;
24+
import org.openjdk.jmh.runner.options.OptionsBuilder;
25+
26+
import com.ibm.fhir.examples.ExamplesUtil;
27+
import com.ibm.fhir.model.format.Format;
28+
import com.ibm.fhir.model.parser.FHIRParser;
29+
import com.ibm.fhir.model.resource.ValueSet;
30+
import com.ibm.fhir.model.resource.ValueSet.Expansion.Contains;
31+
import com.ibm.fhir.model.type.Code;
32+
import com.ibm.fhir.model.type.DateTime;
33+
import com.ibm.fhir.model.type.Uri;
34+
import com.ibm.fhir.model.type.code.PublicationStatus;
35+
36+
public class FHIRValueSetBenchmarks {
37+
@Benchmark
38+
public ValueSet readJsonResource() throws Exception {
39+
Reader reader = ExamplesUtil.reader("json/ibm/valueset/ValueSet-large.json");
40+
return FHIRParser.parser(Format.JSON).parse(reader);
41+
}
42+
43+
@Benchmark
44+
public ValueSet readXmlResource() throws Exception {
45+
Reader reader = ExamplesUtil.reader("xml/ibm/valueset/ValueSet-large.xml");
46+
return FHIRParser.parser(Format.XML).parse(reader);
47+
}
48+
49+
@Benchmark
50+
public ValueSet readTxtFile() throws Exception {
51+
final ValueSet.Builder vsBuilder = ValueSet.builder().status(PublicationStatus.DRAFT);
52+
final ValueSet.Expansion.Builder expansionBuilder = ValueSet.Expansion.builder().timestamp(DateTime.now());
53+
final ValueSet.Expansion.Contains.Builder template = ValueSet.Expansion.Contains.builder();
54+
55+
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("ValueSet-large.txt");
56+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
57+
reader.lines()
58+
.forEach(line -> {
59+
String[] concept = line.split("|");
60+
expansionBuilder.contains(template
61+
.system(Uri.of(concept[0]))
62+
.code(Code.of(concept[1]))
63+
.build()
64+
);
65+
});
66+
}
67+
return vsBuilder.expansion(expansionBuilder.build()).build();
68+
}
69+
70+
@SuppressWarnings("unchecked")
71+
@Benchmark
72+
public Set<String> readSerializedSet() throws Exception {
73+
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("ValueSet-large-HashSet.ser");
74+
try (ObjectInputStream is = new ObjectInputStream(in)) {
75+
return (Set<String>) is.readObject();
76+
}
77+
}
78+
79+
@State(Scope.Benchmark)
80+
public static class FHIRValueSetState {
81+
ValueSet valueSet;
82+
Contains concept;
83+
84+
@Setup
85+
public void setUp() throws Exception {
86+
Reader reader = ExamplesUtil.reader("json/ibm/valueset/ValueSet-large.json");
87+
valueSet = FHIRParser.parser(Format.JSON).parse(reader);
88+
89+
List<Contains> concepts = valueSet.getExpansion().getContains();
90+
// naive attempt to force the worst case
91+
concept = concepts.get(concepts.size() - 1);
92+
}
93+
}
94+
95+
@Benchmark
96+
public Set<String> buildSet(FHIRValueSetState state) throws Exception {
97+
final Set<String> set = new HashSet<>();
98+
state.valueSet.getExpansion().getContains().stream()
99+
.forEach(concept -> set.add(concept.getSystem().getValue() + "|" + concept.getCode().getValue()));
100+
return set;
101+
}
102+
103+
@Benchmark
104+
public boolean lookupInList(FHIRValueSetState state) throws Exception {
105+
for (ValueSet.Expansion.Contains concept : state.valueSet.getExpansion().getContains()) {
106+
if (state.concept.getCode().equals(concept.getCode()) && state.concept.getSystem().equals(concept.getSystem())) {
107+
return true;
108+
}
109+
}
110+
return false;
111+
}
112+
113+
@State(Scope.Benchmark)
114+
public static class FHIRHashSetState {
115+
Set<String> set;
116+
117+
@SuppressWarnings("unchecked")
118+
@Setup
119+
public void setUp() throws Exception {
120+
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("ValueSet-large-HashSet.ser");
121+
try (ObjectInputStream is = new ObjectInputStream(in)) {
122+
set = (Set<String>) is.readObject();
123+
}
124+
}
125+
}
126+
127+
@Benchmark
128+
public boolean lookupInSet(FHIRValueSetState vsState, FHIRHashSetState state) throws Exception {
129+
return state.set.contains(vsState.concept.getSystem().getValue() + "|" + vsState.concept.getCode().getValue());
130+
}
131+
132+
public static void main(String[] args) throws Exception {
133+
// new FHIRBenchmarkRunner(FHIRValueSetBenchmark.class).run(BenchmarkUtil.getRandomSpecExampleName());
134+
Options opt = new OptionsBuilder()
135+
.include(FHIRValueSetBenchmarks.class.getSimpleName())
136+
.warmupIterations(3)
137+
.measurementIterations(2)
138+
.forks(1)
139+
.build();
140+
141+
new Runner(opt).run();
142+
}
143+
}

0 commit comments

Comments
 (0)