tree-walk: report recursion counts

The traverse_trees() method recursively walks through trees, but also prunes the tree-walk based on a callback. Some callers, such as unpack_trees(), are quite complicated and can have wildly different performance between two different commands. Create constants that count these values and then report the results at the end of a process. These counts are cumulative across multiple "root" instances of traverse_trees(), but they provide reproducible values for demonstrating improvements to the pruning algorithm when possible. This change is modeled after a similar statistics reporting in 42e50e78 (revision.c: add trace2 stats around Bloom filter usage, 2020-04-06). Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Jan 4, 2021 at 03:09 UTC da8be8ced672fc00d5dea8a95d04854b2e35d925
1 file changed +33
tree-walk.c
+33
@@ -4,6 +4,7 @@
4 #include "object-store.h"
5 #include "tree.h"
6 #include "pathspec.h"
7 +#include "json-writer.h"
8
9 static const char *get_mode(const char *str, unsigned int *modep)
10 {
@@ -167,6 +168,25 @@ int tree_entry_gently(struct tree_desc *desc, struct name_entry *entry)
168 return 1;
169 }
170
171 +static int traverse_trees_atexit_registered;
172 +static int traverse_trees_count;
173 +static int traverse_trees_cur_depth;
174 +static int traverse_trees_max_depth;
175 +
176 +static void trace2_traverse_trees_statistics_atexit(void)
177 +{
178 + struct json_writer jw = JSON_WRITER_INIT;
179 +
180 + jw_object_begin(&jw, 0);
181 + jw_object_intmax(&jw, "traverse_trees_count", traverse_trees_count);
182 + jw_object_intmax(&jw, "traverse_trees_max_depth", traverse_trees_max_depth);
183 + jw_end(&jw);
184 +
185 + trace2_data_json("traverse_trees", the_repository, "statistics", &jw);
186 +
187 + jw_release(&jw);
188 +}
189 +
190 void setup_traverse_info(struct traverse_info *info, const char *base)
191 {
192 size_t pathlen = strlen(base);
@@ -180,6 +200,11 @@ void setup_traverse_info(struct traverse_info *info, const char *base)
200 info->namelen = pathlen;
201 if (pathlen)
202 info->prev = &dummy;
203 +
204 + if (trace2_is_enabled() && !traverse_trees_atexit_registered) {
205 + atexit(trace2_traverse_trees_statistics_atexit);
206 + traverse_trees_atexit_registered = 1;
207 + }
208 }
209
210 char *make_traverse_path(char *path, size_t pathlen,
@@ -416,6 +441,12 @@ int traverse_trees(struct index_state *istate,
441 int interesting = 1;
442 char *traverse_path;
443
444 + traverse_trees_count++;
445 + traverse_trees_cur_depth++;
446 +
447 + if (traverse_trees_cur_depth > traverse_trees_max_depth)
448 + traverse_trees_max_depth = traverse_trees_cur_depth;
449 +
450 if (n >= ARRAY_SIZE(entry))
451 BUG("traverse_trees() called with too many trees (%d)", n);
452
@@ -515,6 +546,8 @@ int traverse_trees(struct index_state *istate,
546 free(traverse_path);
547 info->traverse_path = NULL;
548 strbuf_release(&base);
549 +
550 + traverse_trees_cur_depth--;
551 return error;
552 }
553