]>
Commit | Line | Data |
---|---|---|
ea194895 JH |
1 | #include "cache.h" |
2 | #include "parse-options.h" | |
3 | ||
4 | static int single; | |
5 | static int multi; | |
6 | static int count = 1; | |
7 | static int dump; | |
8 | static int perf; | |
9 | static int analyze; | |
10 | static int analyze_step; | |
11 | ||
12 | /* | |
13 | * Dump the contents of the "dir" and "name" hash tables to stdout. | |
14 | * If you sort the result, you can compare it with the other type | |
15 | * mode and verify that both single and multi produce the same set. | |
16 | */ | |
17 | static void dump_run(void) | |
18 | { | |
19 | struct hashmap_iter iter_dir; | |
20 | struct hashmap_iter iter_cache; | |
21 | ||
22 | /* Stolen from name-hash.c */ | |
23 | struct dir_entry { | |
24 | struct hashmap_entry ent; | |
25 | struct dir_entry *parent; | |
26 | int nr; | |
27 | unsigned int namelen; | |
28 | char name[FLEX_ARRAY]; | |
29 | }; | |
30 | ||
31 | struct dir_entry *dir; | |
32 | struct cache_entry *ce; | |
33 | ||
34 | read_cache(); | |
35 | if (single) { | |
36 | test_lazy_init_name_hash(&the_index, 0); | |
37 | } else { | |
38 | int nr_threads_used = test_lazy_init_name_hash(&the_index, 1); | |
39 | if (!nr_threads_used) | |
40 | die("non-threaded code path used"); | |
41 | } | |
42 | ||
43 | dir = hashmap_iter_first(&the_index.dir_hash, &iter_dir); | |
44 | while (dir) { | |
45 | printf("dir %08x %7d %s\n", dir->ent.hash, dir->nr, dir->name); | |
46 | dir = hashmap_iter_next(&iter_dir); | |
47 | } | |
48 | ||
49 | ce = hashmap_iter_first(&the_index.name_hash, &iter_cache); | |
50 | while (ce) { | |
51 | printf("name %08x %s\n", ce->ent.hash, ce->name); | |
52 | ce = hashmap_iter_next(&iter_cache); | |
53 | } | |
54 | ||
55 | discard_cache(); | |
56 | } | |
57 | ||
58 | /* | |
59 | * Run the single or multi threaded version "count" times and | |
60 | * report on the time taken. | |
61 | */ | |
62 | static uint64_t time_runs(int try_threaded) | |
63 | { | |
64 | uint64_t t0, t1, t2; | |
65 | uint64_t sum = 0; | |
66 | uint64_t avg; | |
67 | int nr_threads_used; | |
68 | int i; | |
69 | ||
70 | for (i = 0; i < count; i++) { | |
71 | t0 = getnanotime(); | |
72 | read_cache(); | |
73 | t1 = getnanotime(); | |
74 | nr_threads_used = test_lazy_init_name_hash(&the_index, try_threaded); | |
75 | t2 = getnanotime(); | |
76 | ||
77 | sum += (t2 - t1); | |
78 | ||
79 | if (try_threaded && !nr_threads_used) | |
80 | die("non-threaded code path used"); | |
81 | ||
82 | if (nr_threads_used) | |
83 | printf("%f %f %d multi %d\n", | |
84 | ((double)(t1 - t0))/1000000000, | |
85 | ((double)(t2 - t1))/1000000000, | |
86 | the_index.cache_nr, | |
87 | nr_threads_used); | |
88 | else | |
89 | printf("%f %f %d single\n", | |
90 | ((double)(t1 - t0))/1000000000, | |
91 | ((double)(t2 - t1))/1000000000, | |
92 | the_index.cache_nr); | |
93 | fflush(stdout); | |
94 | ||
95 | discard_cache(); | |
96 | } | |
97 | ||
98 | avg = sum / count; | |
99 | if (count > 1) | |
100 | printf("avg %f %s\n", | |
101 | (double)avg/1000000000, | |
102 | (try_threaded) ? "multi" : "single"); | |
103 | ||
104 | return avg; | |
105 | } | |
106 | ||
107 | /* | |
108 | * Try a series of runs varying the "istate->cache_nr" and | |
109 | * try to find a good value for the multi-threaded criteria. | |
110 | */ | |
111 | static void analyze_run(void) | |
112 | { | |
113 | uint64_t t1s, t1m, t2s, t2m; | |
114 | int cache_nr_limit; | |
74dea0e1 | 115 | int nr_threads_used = 0; |
ea194895 JH |
116 | int i; |
117 | int nr; | |
118 | ||
119 | read_cache(); | |
120 | cache_nr_limit = the_index.cache_nr; | |
121 | discard_cache(); | |
122 | ||
123 | nr = analyze; | |
124 | while (1) { | |
125 | uint64_t sum_single = 0; | |
126 | uint64_t sum_multi = 0; | |
127 | uint64_t avg_single; | |
128 | uint64_t avg_multi; | |
129 | ||
130 | if (nr > cache_nr_limit) | |
131 | nr = cache_nr_limit; | |
132 | ||
133 | for (i = 0; i < count; i++) { | |
134 | read_cache(); | |
135 | the_index.cache_nr = nr; /* cheap truncate of index */ | |
136 | t1s = getnanotime(); | |
137 | test_lazy_init_name_hash(&the_index, 0); | |
138 | t2s = getnanotime(); | |
139 | sum_single += (t2s - t1s); | |
140 | the_index.cache_nr = cache_nr_limit; | |
141 | discard_cache(); | |
142 | ||
143 | read_cache(); | |
144 | the_index.cache_nr = nr; /* cheap truncate of index */ | |
145 | t1m = getnanotime(); | |
146 | nr_threads_used = test_lazy_init_name_hash(&the_index, 1); | |
147 | t2m = getnanotime(); | |
148 | sum_multi += (t2m - t1m); | |
149 | the_index.cache_nr = cache_nr_limit; | |
150 | discard_cache(); | |
151 | ||
152 | if (!nr_threads_used) | |
153 | printf(" [size %8d] [single %f] non-threaded code path used\n", | |
154 | nr, ((double)(t2s - t1s))/1000000000); | |
155 | else | |
156 | printf(" [size %8d] [single %f] %c [multi %f %d]\n", | |
157 | nr, | |
158 | ((double)(t2s - t1s))/1000000000, | |
159 | (((t2s - t1s) < (t2m - t1m)) ? '<' : '>'), | |
160 | ((double)(t2m - t1m))/1000000000, | |
161 | nr_threads_used); | |
162 | fflush(stdout); | |
163 | } | |
164 | if (count > 1) { | |
165 | avg_single = sum_single / count; | |
166 | avg_multi = sum_multi / count; | |
167 | if (!nr_threads_used) | |
168 | printf("avg [size %8d] [single %f]\n", | |
169 | nr, | |
170 | (double)avg_single/1000000000); | |
171 | else | |
172 | printf("avg [size %8d] [single %f] %c [multi %f %d]\n", | |
173 | nr, | |
174 | (double)avg_single/1000000000, | |
175 | (avg_single < avg_multi ? '<' : '>'), | |
176 | (double)avg_multi/1000000000, | |
177 | nr_threads_used); | |
178 | fflush(stdout); | |
179 | } | |
180 | ||
181 | if (nr >= cache_nr_limit) | |
182 | return; | |
183 | nr += analyze_step; | |
184 | } | |
185 | } | |
186 | ||
187 | int cmd_main(int argc, const char **argv) | |
188 | { | |
189 | const char *usage[] = { | |
190 | "test-lazy-init-name-hash -d (-s | -m)", | |
191 | "test-lazy-init-name-hash -p [-c c]", | |
192 | "test-lazy-init-name-hash -a a [--step s] [-c c]", | |
193 | "test-lazy-init-name-hash (-s | -m) [-c c]", | |
194 | "test-lazy-init-name-hash -s -m [-c c]", | |
195 | NULL | |
196 | }; | |
197 | struct option options[] = { | |
198 | OPT_BOOL('s', "single", &single, "run single-threaded code"), | |
199 | OPT_BOOL('m', "multi", &multi, "run multi-threaded code"), | |
200 | OPT_INTEGER('c', "count", &count, "number of passes"), | |
201 | OPT_BOOL('d', "dump", &dump, "dump hash tables"), | |
202 | OPT_BOOL('p', "perf", &perf, "compare single vs multi"), | |
203 | OPT_INTEGER('a', "analyze", &analyze, "analyze different multi sizes"), | |
204 | OPT_INTEGER(0, "step", &analyze_step, "analyze step factor"), | |
205 | OPT_END(), | |
206 | }; | |
207 | const char *prefix; | |
208 | uint64_t avg_single, avg_multi; | |
209 | ||
210 | prefix = setup_git_directory(); | |
211 | ||
212 | argc = parse_options(argc, argv, prefix, options, usage, 0); | |
213 | ||
214 | /* | |
215 | * istate->dir_hash is only created when ignore_case is set. | |
216 | */ | |
217 | ignore_case = 1; | |
218 | ||
219 | if (dump) { | |
220 | if (perf || analyze > 0) | |
221 | die("cannot combine dump, perf, or analyze"); | |
222 | if (count > 1) | |
223 | die("count not valid with dump"); | |
224 | if (single && multi) | |
225 | die("cannot use both single and multi with dump"); | |
226 | if (!single && !multi) | |
227 | die("dump requires either single or multi"); | |
228 | dump_run(); | |
229 | return 0; | |
230 | } | |
231 | ||
232 | if (perf) { | |
233 | if (analyze > 0) | |
234 | die("cannot combine dump, perf, or analyze"); | |
235 | if (single || multi) | |
236 | die("cannot use single or multi with perf"); | |
237 | avg_single = time_runs(0); | |
238 | avg_multi = time_runs(1); | |
239 | if (avg_multi > avg_single) | |
240 | die("multi is slower"); | |
241 | return 0; | |
242 | } | |
243 | ||
244 | if (analyze) { | |
245 | if (analyze < 500) | |
246 | die("analyze must be at least 500"); | |
247 | if (!analyze_step) | |
248 | analyze_step = analyze; | |
249 | if (single || multi) | |
250 | die("cannot use single or multi with analyze"); | |
251 | analyze_run(); | |
252 | return 0; | |
253 | } | |
254 | ||
255 | if (!single && !multi) | |
256 | die("require either -s or -m or both"); | |
257 | ||
258 | if (single) | |
259 | time_runs(0); | |
260 | if (multi) | |
261 | time_runs(1); | |
262 | ||
263 | return 0; | |
264 | } |