View Javadoc
1   /*
2    * Copyright (C) 2017, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.pgm.debug;
45  
46  import static java.nio.charset.StandardCharsets.UTF_8;
47  import static org.eclipse.jgit.lib.Constants.HEAD;
48  import static org.eclipse.jgit.lib.Constants.MASTER;
49  import static org.eclipse.jgit.lib.Constants.R_HEADS;
50  import static org.eclipse.jgit.lib.Ref.Storage.NEW;
51  import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
52  
53  import java.io.BufferedReader;
54  import java.io.FileInputStream;
55  import java.io.FileNotFoundException;
56  import java.io.IOException;
57  import java.io.InputStreamReader;
58  
59  import org.eclipse.jgit.internal.storage.io.BlockSource;
60  import org.eclipse.jgit.internal.storage.reftable.RefCursor;
61  import org.eclipse.jgit.internal.storage.reftable.ReftableReader;
62  import org.eclipse.jgit.lib.ObjectId;
63  import org.eclipse.jgit.lib.ObjectIdRef;
64  import org.eclipse.jgit.lib.Ref;
65  import org.eclipse.jgit.lib.SymbolicRef;
66  import org.eclipse.jgit.pgm.Command;
67  import org.eclipse.jgit.pgm.TextBuiltin;
68  import org.eclipse.jgit.util.RefList;
69  import org.kohsuke.args4j.Argument;
70  import org.kohsuke.args4j.Option;
71  
72  @Command
73  class BenchmarkReftable extends TextBuiltin {
74  	enum Test {
75  		SCAN,
76  		SEEK_COLD, SEEK_HOT,
77  		BY_ID_COLD, BY_ID_HOT;
78  	}
79  
80  	@Option(name = "--tries")
81  	private int tries = 10;
82  
83  	@Option(name = "--test")
84  	private Test test = Test.SCAN;
85  
86  	@Option(name = "--ref")
87  	private String ref;
88  
89  	@Option(name = "--object-id")
90  	private String objectId;
91  
92  	@Argument(index = 0)
93  	private String lsRemotePath;
94  
95  	@Argument(index = 1)
96  	private String reftablePath;
97  
98  	@Override
99  	protected void run() throws Exception {
100 		switch (test) {
101 		case SCAN:
102 			scan();
103 			break;
104 
105 		case SEEK_COLD:
106 			seekCold(ref);
107 			break;
108 		case SEEK_HOT:
109 			seekHot(ref);
110 			break;
111 
112 		case BY_ID_COLD:
113 			byIdCold(ObjectId.fromString(objectId));
114 			break;
115 		case BY_ID_HOT:
116 			byIdHot(ObjectId.fromString(objectId));
117 			break;
118 		}
119 	}
120 
121 	private void printf(String fmt, Object... args) throws IOException {
122 		errw.println(String.format(fmt, args));
123 	}
124 
125 	@SuppressWarnings({ "nls", "boxing" })
126 	private void scan() throws Exception {
127 		long start, tot;
128 
129 		start = System.currentTimeMillis();
130 		for (int i = 0; i < tries; i++) {
131 			readLsRemote();
132 		}
133 		tot = System.currentTimeMillis() - start;
134 		printf("%12s %10d ms  %6d ms/run", "packed-refs", tot, tot / tries);
135 
136 		start = System.currentTimeMillis();
137 		for (int i = 0; i < tries; i++) {
138 			try (FileInputStream in = new FileInputStream(reftablePath);
139 					BlockSource src = BlockSource.from(in);
140 					ReftableReader reader = new ReftableReader(src)) {
141 				try (RefCursor rc = reader.allRefs()) {
142 					while (rc.next()) {
143 						rc.getRef();
144 					}
145 				}
146 			}
147 		}
148 		tot = System.currentTimeMillis() - start;
149 		printf("%12s %10d ms  %6d ms/run", "reftable", tot, tot / tries);
150 	}
151 
152 	private RefList<Ref> readLsRemote()
153 			throws IOException, FileNotFoundException {
154 		RefList.Builder<Ref> list = new RefList.Builder<>();
155 		try (BufferedReader br = new BufferedReader(new InputStreamReader(
156 				new FileInputStream(lsRemotePath), UTF_8))) {
157 			Ref last = null;
158 			String line;
159 			while ((line = br.readLine()) != null) {
160 				ObjectId id = ObjectId.fromString(line.substring(0, 40));
161 				String name = line.substring(41, line.length());
162 				if (last != null && name.endsWith("^{}")) { //$NON-NLS-1$
163 					last = new ObjectIdRef.PeeledTag(PACKED, last.getName(),
164 							last.getObjectId(), id);
165 					list.set(list.size() - 1, last);
166 					continue;
167 				}
168 
169 				if (name.equals(HEAD)) {
170 					last = new SymbolicRef(name, new ObjectIdRef.Unpeeled(NEW,
171 							R_HEADS + MASTER, null));
172 				} else {
173 					last = new ObjectIdRef.PeeledNonTag(PACKED, name, id);
174 				}
175 				list.add(last);
176 			}
177 		}
178 		list.sort();
179 		return list.toRefList();
180 	}
181 
182 	@SuppressWarnings({ "nls", "boxing" })
183 	private void seekCold(String refName) throws Exception {
184 		long start, tot;
185 
186 		int lsTries = Math.min(tries, 64);
187 		start = System.nanoTime();
188 		for (int i = 0; i < lsTries; i++) {
189 			readLsRemote().get(refName);
190 		}
191 		tot = System.nanoTime() - start;
192 		printf("%12s %10d usec  %9.1f usec/run  %5d runs", "packed-refs",
193 				tot / 1000,
194 				(((double) tot) / lsTries) / 1000,
195 				lsTries);
196 
197 		start = System.nanoTime();
198 		for (int i = 0; i < tries; i++) {
199 			try (FileInputStream in = new FileInputStream(reftablePath);
200 					BlockSource src = BlockSource.from(in);
201 					ReftableReader reader = new ReftableReader(src)) {
202 				try (RefCursor rc = reader.seekRef(refName)) {
203 					while (rc.next()) {
204 						rc.getRef();
205 					}
206 				}
207 			}
208 		}
209 		tot = System.nanoTime() - start;
210 		printf("%12s %10d usec  %9.1f usec/run  %5d runs", "reftable",
211 				tot / 1000,
212 				(((double) tot) / tries) / 1000,
213 				tries);
214 	}
215 
216 	@SuppressWarnings({ "nls", "boxing" })
217 	private void seekHot(String refName) throws Exception {
218 		long start, tot;
219 
220 		int lsTries = Math.min(tries, 64);
221 		start = System.nanoTime();
222 		RefList<Ref> lsRemote = readLsRemote();
223 		for (int i = 0; i < lsTries; i++) {
224 			lsRemote.get(refName);
225 		}
226 		tot = System.nanoTime() - start;
227 		printf("%12s %10d usec  %9.1f usec/run  %5d runs", "packed-refs",
228 				tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);
229 
230 		start = System.nanoTime();
231 		try (FileInputStream in = new FileInputStream(reftablePath);
232 				BlockSource src = BlockSource.from(in);
233 				ReftableReader reader = new ReftableReader(src)) {
234 			for (int i = 0; i < tries; i++) {
235 				try (RefCursor rc = reader.seekRef(refName)) {
236 					while (rc.next()) {
237 						rc.getRef();
238 					}
239 				}
240 			}
241 		}
242 		tot = System.nanoTime() - start;
243 		printf("%12s %10d usec  %9.1f usec/run  %5d runs", "reftable",
244 				tot / 1000, (((double) tot) / tries) / 1000, tries);
245 	}
246 
247 	@SuppressWarnings({ "nls", "boxing" })
248 	private void byIdCold(ObjectId id) throws Exception {
249 		long start, tot;
250 
251 		int lsTries = Math.min(tries, 64);
252 		start = System.nanoTime();
253 		for (int i = 0; i < lsTries; i++) {
254 			for (Ref r : readLsRemote()) {
255 				if (id.equals(r.getObjectId())) {
256 					continue;
257 				}
258 			}
259 		}
260 		tot = System.nanoTime() - start;
261 		printf("%12s %10d usec  %9.1f usec/run  %5d runs", "packed-refs",
262 				tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);
263 
264 		start = System.nanoTime();
265 		for (int i = 0; i < tries; i++) {
266 			try (FileInputStream in = new FileInputStream(reftablePath);
267 					BlockSource src = BlockSource.from(in);
268 					ReftableReader reader = new ReftableReader(src)) {
269 				try (RefCursor rc = reader.byObjectId(id)) {
270 					while (rc.next()) {
271 						rc.getRef();
272 					}
273 				}
274 			}
275 		}
276 		tot = System.nanoTime() - start;
277 		printf("%12s %10d usec  %9.1f usec/run  %5d runs", "reftable",
278 				tot / 1000, (((double) tot) / tries) / 1000, tries);
279 	}
280 
281 	@SuppressWarnings({ "nls", "boxing" })
282 	private void byIdHot(ObjectId id) throws Exception {
283 		long start, tot;
284 
285 		int lsTries = Math.min(tries, 64);
286 		start = System.nanoTime();
287 		RefList<Ref> lsRemote = readLsRemote();
288 		for (int i = 0; i < lsTries; i++) {
289 			for (Ref r : lsRemote) {
290 				if (id.equals(r.getObjectId())) {
291 					continue;
292 				}
293 			}
294 		}
295 		tot = System.nanoTime() - start;
296 		printf("%12s %10d usec  %9.1f usec/run  %5d runs", "packed-refs",
297 				tot / 1000, (((double) tot) / lsTries) / 1000, lsTries);
298 
299 		start = System.nanoTime();
300 		try (FileInputStream in = new FileInputStream(reftablePath);
301 				BlockSource src = BlockSource.from(in);
302 				ReftableReader reader = new ReftableReader(src)) {
303 			for (int i = 0; i < tries; i++) {
304 				try (RefCursor rc = reader.byObjectId(id)) {
305 					while (rc.next()) {
306 						rc.getRef();
307 					}
308 				}
309 			}
310 		}
311 		tot = System.nanoTime() - start;
312 		printf("%12s %10d usec  %9.1f usec/run  %5d runs", "reftable",
313 				tot / 1000, (((double) tot) / tries) / 1000, tries);
314 	}
315 }