-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
StaticPlaceholderBenchmark.java
192 lines (161 loc) · 7.7 KB
/
StaticPlaceholderBenchmark.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package ru.progrm_jarvis.ultimatemessenger;
import lombok.NonNull;
import lombok.val;
import lombok.var;
import org.jetbrains.annotations.Nullable;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import ru.progrm_jarvis.javacommons.pair.Pair;
import ru.progrm_jarvis.javacommons.pair.SimplePair;
import ru.progrm_jarvis.ultimatemessenger.format.model.AsmTextModelFactory;
import ru.progrm_jarvis.ultimatemessenger.format.model.SimpleTextModelFactory;
import ru.progrm_jarvis.ultimatemessenger.format.model.TextModel;
import ru.progrm_jarvis.ultimatemessenger.format.placeholder.Placeholders;
import ru.progrm_jarvis.ultimatemessenger.format.placeholder.SimplePlaceholders;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
@Threads(Threads.MAX)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class StaticPlaceholderBenchmark {
public static void main(@NonNull final String[] args) throws RunnerException {
new Runner(new OptionsBuilder().build()).run();
}
@Benchmark
public void stringReplace(final Blackhole blackhole,
final Configuration configuration,
final StringReplaceConfiguration stringReplaceConfiguration) {
for (var text : stringReplaceConfiguration.texts) {
for (val replacement : configuration.replacements.entrySet()) text
= text.replace(replacement.getKey(), replacement.getValue());
blackhole.consume(text);
}
}
@Benchmark
public void regex(final Blackhole blackhole,
final Configuration configuration,
final RegexConfiguration regexConfiguration) {
for (val text : regexConfiguration.texts) {
val matcher = regexConfiguration.placeholderPattern.matcher(text);
val result = new StringBuffer(); // this is not okay, but hi Java 8 support
while (matcher.find()) {
val group = matcher.group(1);
matcher.appendReplacement(result, configuration.replacements.get(group));
}
matcher.appendTail(result);
blackhole.consume(result.toString());
}
}
@Benchmark
public void simplePlaceholdersWithSimpleTmf(final Blackhole blackhole,
final SimpleTmfPlaceholdersConfiguration placeholdersConfiguration) {
for (val text : placeholdersConfiguration.texts) blackhole.consume(text.getText(null));
}
@Benchmark
public void simplePlaceholdersWithAsmTmf(final Blackhole blackhole,
final AsmTmfPlaceholdersConfiguration placeholdersConfiguration) {
for (val text : placeholdersConfiguration.texts) blackhole.consume(text.getText(null));
}
/**
* Basic generated configuration.
*/
@State(Scope.Benchmark)
public static class Configuration {
protected final Map<String, String> replacements = new HashMap<>();
protected final List<Pair<String, String>> textPairs = new ArrayList<>();
@Param({"1", "2", "10", "30", "50", "100"})
private int replacementsCount;
@Param({"1", "5", "10", "100", "1000"})
private int rawTextsCount;
@Setup
public void setup() {
val random = ThreadLocalRandom.current();
val indexedReplacements = new String[replacementsCount];
for (var i = 0; i < replacementsCount; i++) {
final String placeholder = "placeholder#" + i, replacement = Integer.toHexString(random.nextInt());
replacements.put(placeholder, replacement);
indexedReplacements[i] = replacement;
}
for (var i = 0; i < rawTextsCount; i++) {
val raw = new StringBuilder();
val formatted = new StringBuilder();
val textBlocks = random.nextInt(0xFF);
for (var blockIndex = random.nextBoolean() ? 0 : 1;
blockIndex < textBlocks; blockIndex++) if ((blockIndex & 0b1) == 0) {
// add plain text
val text = new StringBuilder();
val textLength = random.nextInt(0xF);
for (var textSubBlock = 0; textSubBlock < textLength; textSubBlock++) text
.append(Integer.toHexString(random.nextInt()));
raw.append(text);
formatted.append(text);
} else {
val placeholerId = random.nextInt(replacementsCount);
raw.append("{placeholder#").append(placeholerId).append('}');
formatted.append(indexedReplacements[placeholerId]);
}
textPairs.add(SimplePair.of(raw.toString(), formatted.toString()));
}
}
}
@State(Scope.Benchmark)
public static class StringReplaceConfiguration {
private final List<String> texts = new ArrayList<>();
@Setup
public void setup(final Configuration configuration) {
for (val textPair : configuration.textPairs) texts.add(textPair.getFirst());
}
}
@State(Scope.Benchmark)
public static class RegexConfiguration {
// don't know why but Intellij forces escaping of `{`
private final Pattern placeholderPattern = Pattern.compile("\\{(.*?)}");
private final List<String> texts = new ArrayList<>();
@Setup
public void setup(final Configuration configuration) {
for (val textPair : configuration.textPairs) texts.add(textPair.getFirst());
}
}
@State(Scope.Benchmark)
public static class PlaceholdersConfiguration {
protected final Placeholders<Object> placeholders = SimplePlaceholders.builder().build();
@Setup
public void setup(final Configuration configuration) {
for (val replacement : configuration.replacements.entrySet())
placeholders.add(
// it is fair to get the value each time from map as regex implementation will have to do so
replacement.getKey(), (source, target) -> replacement.getValue()
);
}
}
@State(Scope.Benchmark)
public static class SimpleTmfPlaceholdersConfiguration {
private final List<TextModel<@Nullable ?>> texts = new ArrayList<>();
@Setup
public void setup(final Configuration configuration,
final PlaceholdersConfiguration placeholdersConfiguration) {
val textModelFactory = SimpleTextModelFactory.<Object>get();
for (val textPair : configuration.textPairs) texts
.add(placeholdersConfiguration.placeholders.parse(textModelFactory, textPair.getFirst()));
}
}
@State(Scope.Benchmark)
public static class AsmTmfPlaceholdersConfiguration {
private final List<TextModel<@Nullable ?>> texts = new ArrayList<>();
@Setup
public void setup(final Configuration configuration,
final PlaceholdersConfiguration placeholdersConfiguration) {
val textModelFactory = AsmTextModelFactory.<Object>get();
for (val textPair : configuration.textPairs) texts
.add(placeholdersConfiguration.placeholders.parse(textModelFactory, textPair.getFirst()));
}
}
}