View Javadoc
1   /*
2    * Copyright (C) 2017, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
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  	/** {@inheritDoc} */
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("^{}")) { //$NON-NLS-1$
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 }