1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.pgm.debug;
12
13 import static java.nio.charset.StandardCharsets.UTF_8;
14 import static org.eclipse.jgit.lib.Constants.HEAD;
15 import static org.eclipse.jgit.lib.Constants.MASTER;
16 import static org.eclipse.jgit.lib.Constants.R_HEADS;
17 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
18 import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
19
20 import java.io.BufferedReader;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.InputStreamReader;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.stream.Collectors;
29
30 import org.eclipse.jgit.internal.storage.file.FileReftableStack;
31 import org.eclipse.jgit.internal.storage.io.BlockSource;
32 import org.eclipse.jgit.internal.storage.reftable.RefCursor;
33 import org.eclipse.jgit.internal.storage.reftable.ReftableReader;
34 import org.eclipse.jgit.lib.Config;
35 import org.eclipse.jgit.lib.ObjectId;
36 import org.eclipse.jgit.lib.ObjectIdRef;
37 import org.eclipse.jgit.lib.Ref;
38 import org.eclipse.jgit.lib.SymbolicRef;
39 import org.eclipse.jgit.pgm.Command;
40 import org.eclipse.jgit.pgm.TextBuiltin;
41 import org.eclipse.jgit.util.RefList;
42 import org.kohsuke.args4j.Argument;
43 import org.kohsuke.args4j.Option;
44
45 @Command
46 class BenchmarkReftable extends TextBuiltin {
47 enum Test {
48 SCAN,
49 SEEK_COLD, SEEK_HOT,
50 BY_ID_COLD, BY_ID_HOT,
51 WRITE_STACK,
52 GET_REFS_EXCLUDING_REF
53 }
54
55 @Option(name = "--tries")
56 private int tries = 10;
57
58 @Option(name = "--test")
59 private Test test = Test.SCAN;
60
61 @Option(name = "--ref")
62 private String ref;
63
64 @Option(name = "--object-id")
65 private String objectId;
66
67 @Argument(index = 0)
68 private String lsRemotePath;
69
70 @Argument(index = 1)
71 private String reftablePath;
72
73
74 @Override
75 protected void run() throws Exception {
76 switch (test) {
77 case SCAN:
78 scan();
79 break;
80
81 case SEEK_COLD:
82 seekCold(ref);
83 break;
84 case SEEK_HOT:
85 seekHot(ref);
86 break;
87
88 case BY_ID_COLD:
89 byIdCold(ObjectId.fromString(objectId));
90 break;
91 case BY_ID_HOT:
92 byIdHot(ObjectId.fromString(objectId));
93 break;
94 case WRITE_STACK:
95 writeStack();
96 break;
97 case GET_REFS_EXCLUDING_REF :
98 getRefsExcludingWithSeekPast(ref);
99 getRefsExcludingWithFilter(ref);
100 break;
101 }
102 }
103
104 private void printf(String fmt, Object... args) throws IOException {
105 errw.println(String.format(fmt, args));
106 }
107
108 @SuppressWarnings({ "nls", "boxing" })
109 private void writeStack() throws Exception {
110 File dir = new File(reftablePath);
111 File stackFile = new File(reftablePath + ".stack");
112
113 dir.mkdirs();
114
115 long start = System.currentTimeMillis();
116 try (FileReftableStack stack = new FileReftableStack(stackFile, dir,
117 null, () -> new Config())) {
118
119 List<Ref> refs = readLsRemote().asList();
120 for (Ref r : refs) {
121 final long j = stack.getMergedReftable().maxUpdateIndex() + 1;
122 if (!stack.addReftable(w -> {
123 w.setMaxUpdateIndex(j).setMinUpdateIndex(j).begin()
124 .writeRef(r);
125 })) {
126 throw new IOException("should succeed");
127 }
128 }
129 long dt = System.currentTimeMillis() - start;
130 printf("%12s %10d ms avg %6d us/write", "reftable", dt,
131 (dt * 1000) / refs.size());
132 }
133 }
134
135 @SuppressWarnings({ "nls", "boxing" })
136 private void scan() throws Exception {
137 long start, tot;
138
139 start = System.currentTimeMillis();
140 for (int i = 0; i < tries; i++) {
141 readLsRemote();
142 }
143 tot = System.currentTimeMillis() - start;
144 printf("%12s %10d ms %6d ms/run", "packed-refs", tot, tot / tries);
145
146 start = System.currentTimeMillis();
147 for (int i = 0; i < tries; i++) {
148 try (FileInputStream in = new FileInputStream(reftablePath);
149 BlockSource src = BlockSource.from(in);
150 ReftableReader reader = new ReftableReader(src)) {
151 try (RefCursor rc = reader.allRefs()) {
152 while (rc.next()) {
153 rc.getRef();
154 }
155 }
156 }
157 }
158 tot = System.currentTimeMillis() - start;
159 printf("%12s %10d ms %6d ms/run", "reftable", tot, tot / tries);
160 }
161
162 private RefList<Ref> readLsRemote()
163 throws IOException, FileNotFoundException {
164 RefList.Builder<Ref> list = new RefList.Builder<>();
165 try (BufferedReader br = new BufferedReader(new InputStreamReader(
166 new FileInputStream(lsRemotePath), UTF_8))) {
167 Ref last = null;
168 String line;
169 while ((line = br.readLine()) != null) {
170 ObjectId id = ObjectId.fromString(line.substring(0, 40));
171 String name = line.substring(41, line.length());
172 if (last != null && name.endsWith("^{}")) {
173 last = new ObjectIdRef.PeeledTag(PACKED, last.getName(),
174 last.getObjectId(), id);
175 list.set(list.size() - 1, last);
176 continue;
177 }
178
179 if (name.equals(HEAD)) {
180 last = new SymbolicRef(name, new ObjectIdRef.Unpeeled(NEW,
181 R_HEADS + MASTER, null));
182 } else {
183 last = new ObjectIdRef.PeeledNonTag(PACKED, name, id);
184 }
185 list.add(last);
186 }
187 }
188 list.sort();
189 return list.toRefList();
190 }
191
192 @SuppressWarnings({ "nls", "boxing" })
193 private void seekCold(String refName) throws Exception {
194 long start, tot;
195
196 int lsTries = Math.min(tries, 64);
197 start = System.nanoTime();
198 for (int i = 0; i < lsTries; i++) {
199 readLsRemote().get(refName);
200 }
201 tot = System.nanoTime() - start;
202 printf("%12s %10d usec %9.1f usec/run %5d runs", "packed-refs",
203 tot / 1000,
204 (((double) tot) / lsTries) / 1000,
205 lsTries);
206
207 start = System.nanoTime();
208 for (int i = 0; i < tries; i++) {
209 try (FileInputStream in = new FileInputStream(reftablePath);
210 BlockSource src = BlockSource.from(in);
211 ReftableReader reader = new ReftableReader(src)) {
212 try (RefCursor rc = reader.seekRef(refName)) {
213 while (rc.next()) {
214 rc.getRef();
215 }
216 }
217 }
218 }
219 tot = System.nanoTime() - start;
220 printf("%12s %10d usec %9.1f usec/run %5d runs", "reftable",
221 tot / 1000,
222 (((double) tot) / tries) / 1000,
223 tries);
224 }
225
226 @SuppressWarnings({ "nls", "boxing" })
227 private void seekHot(String refName) throws Exception {
228 long start, tot;
229
230 int lsTries = Math.min(tries, 64);
231 start = System.nanoTime();
232 RefList<Ref> lsRemote = readLsRemote();
233 for (int i = 0; i < lsTries; i++) {
234 lsRemote.get(refName);
235 }
236 tot = System.nanoTime() - start;
237 printf("%12s %10d usec %9.1f usec/run %5d runs", "packed-refs",
238 tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);
239
240 start = System.nanoTime();
241 try (FileInputStream in = new FileInputStream(reftablePath);
242 BlockSource src = BlockSource.from(in);
243 ReftableReader reader = new ReftableReader(src)) {
244 for (int i = 0; i < tries; i++) {
245 try (RefCursor rc = reader.seekRef(refName)) {
246 while (rc.next()) {
247 rc.getRef();
248 }
249 }
250 }
251 }
252 tot = System.nanoTime() - start;
253 printf("%12s %10d usec %9.1f usec/run %5d runs", "reftable",
254 tot / 1000, (((double) tot) / tries) / 1000, tries);
255 }
256
257 @SuppressWarnings({ "nls", "boxing" })
258 private void byIdCold(ObjectId id) throws Exception {
259 long start, tot;
260
261 int lsTries = Math.min(tries, 64);
262 start = System.nanoTime();
263 for (int i = 0; i < lsTries; i++) {
264 for (Ref r : readLsRemote()) {
265 if (id.equals(r.getObjectId())) {
266 continue;
267 }
268 }
269 }
270 tot = System.nanoTime() - start;
271 printf("%12s %10d usec %9.1f usec/run %5d runs", "packed-refs",
272 tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);
273
274 start = System.nanoTime();
275 for (int i = 0; i < tries; i++) {
276 try (FileInputStream in = new FileInputStream(reftablePath);
277 BlockSource src = BlockSource.from(in);
278 ReftableReader reader = new ReftableReader(src)) {
279 try (RefCursor rc = reader.byObjectId(id)) {
280 while (rc.next()) {
281 rc.getRef();
282 }
283 }
284 }
285 }
286 tot = System.nanoTime() - start;
287 printf("%12s %10d usec %9.1f usec/run %5d runs", "reftable",
288 tot / 1000, (((double) tot) / tries) / 1000, tries);
289 }
290
291 @SuppressWarnings({ "nls", "boxing" })
292 private void byIdHot(ObjectId id) throws Exception {
293 long start, tot;
294
295 int lsTries = Math.min(tries, 64);
296 start = System.nanoTime();
297 RefList<Ref> lsRemote = readLsRemote();
298 for (int i = 0; i < lsTries; i++) {
299 for (Ref r : lsRemote) {
300 if (id.equals(r.getObjectId())) {
301 continue;
302 }
303 }
304 }
305 tot = System.nanoTime() - start;
306 printf("%12s %10d usec %9.1f usec/run %5d runs", "packed-refs",
307 tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);
308
309 start = System.nanoTime();
310 try (FileInputStream in = new FileInputStream(reftablePath);
311 BlockSource src = BlockSource.from(in);
312 ReftableReader reader = new ReftableReader(src)) {
313 for (int i = 0; i < tries; i++) {
314 try (RefCursor rc = reader.byObjectId(id)) {
315 while (rc.next()) {
316 rc.getRef();
317 }
318 }
319 }
320 }
321 tot = System.nanoTime() - start;
322 printf("%12s %10d usec %9.1f usec/run %5d runs", "reftable",
323 tot / 1000, (((double) tot) / tries) / 1000, tries);
324 }
325
326 @SuppressWarnings({"nls", "boxing"})
327 private void getRefsExcludingWithFilter(String prefix) throws Exception {
328 long startTime = System.nanoTime();
329 List<Ref> allRefs = new ArrayList<>();
330 try (FileInputStream in = new FileInputStream(reftablePath);
331 BlockSource src = BlockSource.from(in);
332 ReftableReader reader = new ReftableReader(src)) {
333 try (RefCursor rc = reader.allRefs()) {
334 while (rc.next()) {
335 allRefs.add(rc.getRef());
336 }
337 }
338 }
339 int total = allRefs.size();
340 allRefs = allRefs.stream().filter(r -> r.getName().startsWith(prefix)).collect(Collectors.toList());
341 int notStartWithPrefix = allRefs.size();
342 int startWithPrefix = total - notStartWithPrefix;
343 long totalTime = System.nanoTime() - startTime;
344 printf("total time the action took using filter: %10d usec", totalTime / 1000);
345 printf("number of refs that start with prefix: %d", startWithPrefix);
346 printf("number of refs that don't start with prefix: %d", notStartWithPrefix);
347 }
348
349 @SuppressWarnings({"nls", "boxing"})
350 private void getRefsExcludingWithSeekPast(String prefix) throws Exception {
351 long start = System.nanoTime();
352 try (FileInputStream in = new FileInputStream(reftablePath);
353 BlockSource src = BlockSource.from(in);
354 ReftableReader reader = new ReftableReader(src)) {
355 try (RefCursor rc = reader.allRefs()) {
356 while (rc.next()) {
357 if (rc.getRef().getName().startsWith(prefix)) {
358 break;
359 }
360 }
361 rc.seekPastPrefix(prefix);
362 while (rc.next()) {
363 rc.getRef();
364 }
365 }
366 }
367 long tot = System.nanoTime() - start;
368 printf("total time the action took using seek: %10d usec", tot / 1000);
369 }
370 }