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