1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.benchmarks;
11
12 import static org.eclipse.jgit.transport.ReceiveCommand.Type.CREATE;
13
14 import java.io.IOException;
15 import java.nio.file.Files;
16 import java.nio.file.Path;
17 import java.nio.file.Paths;
18 import java.util.ArrayList;
19 import java.util.List;
20 import java.util.concurrent.ThreadLocalRandom;
21 import java.util.concurrent.TimeUnit;
22 import java.util.stream.Collectors;
23 import java.util.stream.IntStream;
24
25 import org.eclipse.jgit.api.Git;
26 import org.eclipse.jgit.api.errors.GitAPIException;
27 import org.eclipse.jgit.internal.storage.file.FileRepository;
28 import org.eclipse.jgit.lib.BatchRefUpdate;
29 import org.eclipse.jgit.lib.ConfigConstants;
30 import org.eclipse.jgit.lib.Constants;
31 import org.eclipse.jgit.lib.ObjectId;
32 import org.eclipse.jgit.lib.Repository;
33 import org.eclipse.jgit.lib.RepositoryCache;
34 import org.eclipse.jgit.lib.StoredConfig;
35 import org.eclipse.jgit.lib.TextProgressMonitor;
36 import org.eclipse.jgit.revwalk.RevCommit;
37 import org.eclipse.jgit.revwalk.RevWalk;
38 import org.eclipse.jgit.transport.ReceiveCommand;
39 import org.eclipse.jgit.util.FS;
40 import org.eclipse.jgit.util.FileUtils;
41 import org.openjdk.jmh.annotations.Benchmark;
42 import org.openjdk.jmh.annotations.BenchmarkMode;
43 import org.openjdk.jmh.annotations.Measurement;
44 import org.openjdk.jmh.annotations.Mode;
45 import org.openjdk.jmh.annotations.OutputTimeUnit;
46 import org.openjdk.jmh.annotations.Param;
47 import org.openjdk.jmh.annotations.Scope;
48 import org.openjdk.jmh.annotations.Setup;
49 import org.openjdk.jmh.annotations.State;
50 import org.openjdk.jmh.annotations.TearDown;
51 import org.openjdk.jmh.annotations.Warmup;
52 import org.openjdk.jmh.infra.Blackhole;
53 import org.openjdk.jmh.runner.Runner;
54 import org.openjdk.jmh.runner.RunnerException;
55 import org.openjdk.jmh.runner.options.Options;
56 import org.openjdk.jmh.runner.options.OptionsBuilder;
57
58 @State(Scope.Thread)
59 public class GetRefsBenchmark {
60
61 ThreadLocalRandom branchIndex = ThreadLocalRandom.current();
62
63 @State(Scope.Benchmark)
64 public static class BenchmarkState {
65
66 @Param({ "true", "false" })
67 boolean useRefTable;
68
69 @Param({ "100", "2500", "10000", "50000" })
70 int numBranches;
71
72 @Param({ "true", "false" })
73 boolean trustFolderStat;
74
75 List<String> branches = new ArrayList<>(numBranches);
76
77 Path testDir;
78
79 Repository repo;
80
81 @Setup
82 @SuppressWarnings("boxing")
83 public void setupBenchmark() throws IOException, GitAPIException {
84 String firstBranch = "firstbranch";
85 testDir = Files.createDirectory(Paths.get("testrepos"));
86 String repoName = "branches-" + numBranches + "-trustFolderStat-"
87 + trustFolderStat + "-" + refDatabaseType();
88 Path workDir = testDir.resolve(repoName);
89 Path repoPath = workDir.resolve(".git");
90 Git git = Git.init().setDirectory(workDir.toFile()).call();
91 RevCommit firstCommit = git.commit().setMessage("First commit")
92 .call();
93 git.branchCreate().setName(firstBranch).call();
94
95 StoredConfig cfg = git.getRepository().getConfig();
96 if (useRefTable) {
97 ((FileRepository) git.getRepository()).convertRefStorage(
98 ConfigConstants.CONFIG_REF_STORAGE_REFTABLE, false,
99 false);
100 } else {
101 cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
102 ConfigConstants.CONFIG_KEY_TRUSTFOLDERSTAT,
103 trustFolderStat);
104 }
105 cfg.setInt(ConfigConstants.CONFIG_RECEIVE_SECTION, null,
106 "maxCommandBytes", Integer.MAX_VALUE);
107 cfg.save();
108
109 repo = RepositoryCache.open(RepositoryCache.FileKey
110 .lenient(repoPath.toFile(), FS.DETECTED));
111
112 System.out.println("Preparing test");
113 System.out.println("- repository: \t\t" + repoPath);
114 System.out.println("- refDatabase: \t\t" + refDatabaseType());
115 System.out.println("- trustFolderStat: \t" + trustFolderStat);
116 System.out.println("- branches: \t\t" + numBranches);
117
118 BatchRefUpdate u = repo.getRefDatabase().newBatchUpdate();
119
120 branches = IntStream.range(0, numBranches)
121 .mapToObj(i -> "branch/" + i % 100 + "/" + i)
122 .collect(Collectors.toList());
123 for (String branch : branches) {
124 u.addCommand(new ReceiveCommand(ObjectId.zeroId(),
125 firstCommit.toObjectId(), Constants.R_HEADS + branch,
126 CREATE));
127 }
128
129 System.out.println();
130 System.out.print(
131 String.format("Creating %d branches ... ", numBranches));
132
133 try (RevWalk rw = new RevWalk(repo)) {
134 u.execute(rw, new TextProgressMonitor());
135 }
136 System.out.println("DONE");
137 }
138
139 private String refDatabaseType() {
140 return useRefTable ? "reftable" : "refdir";
141 }
142
143 @TearDown
144 public void teardown() throws IOException {
145 repo.close();
146 FileUtils.delete(testDir.toFile(),
147 FileUtils.RECURSIVE | FileUtils.RETRY);
148 }
149 }
150
151 @Benchmark
152 @BenchmarkMode({ Mode.AverageTime })
153 @OutputTimeUnit(TimeUnit.MICROSECONDS)
154 @Warmup(iterations = 2, time = 100, timeUnit = TimeUnit.MILLISECONDS)
155 @Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.SECONDS)
156 public void testGetExactRef(Blackhole blackhole, BenchmarkState state)
157 throws IOException {
158 String branchName = state.branches
159 .get(branchIndex.nextInt(state.numBranches));
160 blackhole.consume(state.repo.exactRef(branchName));
161 }
162
163 @Benchmark
164 @BenchmarkMode({ Mode.AverageTime })
165 @OutputTimeUnit(TimeUnit.MICROSECONDS)
166 @Warmup(iterations = 2, time = 100, timeUnit = TimeUnit.MILLISECONDS)
167 @Measurement(iterations = 2, time = 10, timeUnit = TimeUnit.SECONDS)
168 public void testGetRefsByPrefix(Blackhole blackhole, BenchmarkState state)
169 throws IOException {
170 String branchPrefix = "refs/heads/branch/" + branchIndex.nextInt(100)
171 + "/";
172 blackhole.consume(
173 state.repo.getRefDatabase().getRefsByPrefix(branchPrefix));
174 }
175
176 public static void main(String[] args) throws RunnerException {
177 Options opt = new OptionsBuilder()
178 .include(GetRefsBenchmark.class.getSimpleName())
179
180
181 .forks(1).jvmArgs("-ea").build();
182 new Runner(opt).run();
183 }
184 }