]> git.ipfire.org Git - thirdparty/git.git/commitdiff
commit-graph: introduce commit_graph_data_slab
authorAbhishek Kumar <abhishekkumar8222@gmail.com>
Wed, 17 Jun 2020 09:14:09 +0000 (14:44 +0530)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Jun 2020 21:37:23 +0000 (14:37 -0700)
The struct commit is used in many contexts. However, members
`generation` and `graph_pos` are only used for commit-graph related
operations and otherwise waste memory.

This wastage would have been more pronounced as we transition to
generation number v2, which uses 64-bit generation number instead of
current 32-bits.

As they are often accessed together, let's introduce struct
commit_graph_data and move them to a commit_graph_data slab.

While the overall test suite runs just as fast as master,
(series: 26m48s, master: 27m34s, faster by 2.87%), certain commands
like `git merge-base --is-ancestor` were slowed by 40% as discovered
by Szeder Gábor [1]. After minimizing commit-slab access, the slow down
persists but is closer to 20%.

Derrick Stolee believes the slow down is attributable to the underlying
algorithm rather than the slowness of commit-slab access [2] and we will
follow-up in a later series.

[1]: https://lore.kernel.org/git/20200607195347.GA8232@szeder.dev/
[2]: https://lore.kernel.org/git/13db757a-9412-7f1e-805c-8a028c4ab2b1@gmail.com/

Signed-off-by: Abhishek Kumar <abhishekkumar8222@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
commit-graph.c
commit-graph.h

index 2ff042fbf4f732f63b6317f9430e1e589df67ef2..8ad7d202b24841faf239b8895b60a8cc264147ff 100644 (file)
@@ -87,6 +87,58 @@ static int commit_pos_cmp(const void *va, const void *vb)
               commit_pos_at(&commit_pos, b);
 }
 
+define_commit_slab(commit_graph_data_slab, struct commit_graph_data);
+static struct commit_graph_data_slab commit_graph_data_slab =
+       COMMIT_SLAB_INIT(1, commit_graph_data_slab);
+
+uint32_t commit_graph_position(const struct commit *c)
+{
+       struct commit_graph_data *data =
+               commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+       return data ? data->graph_pos : COMMIT_NOT_FROM_GRAPH;
+}
+
+uint32_t commit_graph_generation(const struct commit *c)
+{
+       struct commit_graph_data *data =
+               commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+       if (!data)
+               return GENERATION_NUMBER_INFINITY;
+       else if (data->graph_pos == COMMIT_NOT_FROM_GRAPH)
+               return GENERATION_NUMBER_INFINITY;
+
+       return data->generation;
+}
+
+static struct commit_graph_data *commit_graph_data_at(const struct commit *c)
+{
+       unsigned int i, nth_slab;
+       struct commit_graph_data *data =
+               commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+       if (data)
+               return data;
+
+       nth_slab = c->index / commit_graph_data_slab.slab_size;
+       data = commit_graph_data_slab_at(&commit_graph_data_slab, c);
+
+       /*
+        * commit-slab initializes elements with zero, overwrite this with
+        * COMMIT_NOT_FROM_GRAPH for graph_pos.
+        *
+        * We avoid initializing generation with checking if graph position
+        * is not COMMIT_NOT_FROM_GRAPH.
+        */
+       for (i = 0; i < commit_graph_data_slab.slab_size; i++) {
+               commit_graph_data_slab.slab[nth_slab][i].graph_pos =
+                       COMMIT_NOT_FROM_GRAPH;
+       }
+
+       return data;
+}
+
 static int commit_gen_cmp(const void *va, const void *vb)
 {
        const struct commit *a = *(const struct commit **)va;
@@ -1020,7 +1072,7 @@ static void write_graph_chunk_data(struct hashfile *f, int hash_len,
                else
                        packedDate[0] = 0;
 
-               packedDate[0] |= htonl((*list)->generation << 2);
+               packedDate[0] |= htonl(commit_graph_data_at(*list)->generation << 2);
 
                packedDate[1] = htonl((*list)->date);
                hashwrite(f, packedDate, 8);
@@ -1251,9 +1303,11 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
                                        _("Computing commit graph generation numbers"),
                                        ctx->commits.nr);
        for (i = 0; i < ctx->commits.nr; i++) {
+               uint32_t generation = commit_graph_data_at(ctx->commits.list[i])->generation;
+
                display_progress(ctx->progress, i + 1);
-               if (ctx->commits.list[i]->generation != GENERATION_NUMBER_INFINITY &&
-                   ctx->commits.list[i]->generation != GENERATION_NUMBER_ZERO)
+               if (generation != GENERATION_NUMBER_INFINITY &&
+                   generation != GENERATION_NUMBER_ZERO)
                        continue;
 
                commit_list_insert(ctx->commits.list[i], &list);
@@ -1264,22 +1318,26 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)
                        uint32_t max_generation = 0;
 
                        for (parent = current->parents; parent; parent = parent->next) {
-                               if (parent->item->generation == GENERATION_NUMBER_INFINITY ||
-                                   parent->item->generation == GENERATION_NUMBER_ZERO) {
+                               generation = commit_graph_data_at(parent->item)->generation;
+
+                               if (generation == GENERATION_NUMBER_INFINITY ||
+                                   generation == GENERATION_NUMBER_ZERO) {
                                        all_parents_computed = 0;
                                        commit_list_insert(parent->item, &list);
                                        break;
-                               } else if (parent->item->generation > max_generation) {
-                                       max_generation = parent->item->generation;
+                               } else if (generation > max_generation) {
+                                       max_generation = generation;
                                }
                        }
 
                        if (all_parents_computed) {
-                               current->generation = max_generation + 1;
+                               struct commit_graph_data *data = commit_graph_data_at(current);
+
+                               data->generation = max_generation + 1;
                                pop_commit(&list);
 
-                               if (current->generation > GENERATION_NUMBER_MAX)
-                                       current->generation = GENERATION_NUMBER_MAX;
+                               if (data->generation > GENERATION_NUMBER_MAX)
+                                       data->generation = GENERATION_NUMBER_MAX;
                        }
                }
        }
index 3ba0da1e5f4738823670ba560a34e156946b1b8a..28f89cdf3e577582261c2261698bdd051b530edb 100644 (file)
@@ -135,4 +135,14 @@ void free_commit_graph(struct commit_graph *);
  */
 void disable_commit_graph(struct repository *r);
 
+struct commit_graph_data {
+       uint32_t graph_pos;
+       uint32_t generation;
+};
+
+/*
+ * Commits should be parsed before accessing generation, graph positions.
+ */
+uint32_t commit_graph_generation(const struct commit *);
+uint32_t commit_graph_position(const struct commit *);
 #endif