git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 2/3] commit-slab: avoid large realloc

From
Jeff King <peff@peff.net>
Date
Apr 14, 2013, 15:28 UTC
Message-ID
<20130414152842.GB1544@sigill.intra.peff.net>
In-Reply-To
<1365919489-17553-3-git-send-email-gitster@pobox.com>
On Sat, Apr 13, 2013 at 11:04:48PM -0700, Junio C Hamano wrote:
Show 5 quoted lines
> Instead of using a single "slab" and keep reallocating it as we find
> that we need to deal with commits with larger values of commit->index,
> make a "slab" an array of many "slab_piece"s. Each access may need
> two levels of indirections, but we only need to reallocate the first
> level array of pointers when we have to grow the table this way.

I don't know if shrinking the size of the realloc is all that big a deal. We are doubling, so the allocation cost is already amortized constant time.

Whereas the cost of the extra level of indirection is paid for every lookup. So for some workloads, I can imagine this actually being slower (I haven't yet measured it for --topo-order, though).

An interesting side effect of this patch is that the pointers returned by slab_at() are stable until slab_clear(). It doesn't matter for --topo-order, but if, for example, you had a recursive function, you would not have to worry about invalidation in sub-functions. I.e., before this patch, this would be wrong:

  static struct commit_slab generation_cache;
  int commit_generation(struct commit *c)
  {
          int *gp = slab_at(&generation_cache, c);
          if (!*gp) {
                  int max = 0;
                  struct commit_list *p;
                  parse_commit(c);
                  for (p = c->parents; p; p = p->next) {
                          int g = commit_generation(p->item);
                          if (max < g)
                                  max = g;
                  }
                  *gp = max + 1;
          }
          return *gp;
  }

because the recursive calls might invalidate the "gp" pointer (you would have to call slab_at repeatedly instead). Whereas with your patch, it's fine.

Show 7 quoted lines
>  struct commit_slab {
> -	int *buf;
> -	int alloc;
> +	int piece_size;
> +	int piece_count;
> +	struct commit_slab_piece **piece;
>  };

Is there a reason to make piece_size a struct member? It must be constant after any pieces are allocated. Is the intent that callers could do:

  slab_init(&s);
  /* I know ahead of time we are going to need N of these. */
  s.piece_size = n;

? I think that is OK (though they do not need slab_* in that case at all), but we should probably have a warning in the struct that piece_size should never be touched except in that circumstance.

-Peff
Previous: Junio C HamanoNext: Junio C Hamano
Message 6 of 12 in “Using commit slab to replace indegree”
  1. 0/3 Using commit slab to replace indegreeJunio C Hamano, Apr 14, 2013
  2. 1/3 commit: allow associating auxiliary info on-demandJunio C Hamano, Apr 14, 2013
  3. Jeff KingApr 14, 2013
  4. Junio C HamanoApr 14, 2013
  5. 2/3 commit-slab: avoid large reallocJunio C Hamano, Apr 14, 2013
  6. Jeff KingApr 14, 2013
  7. Junio C HamanoApr 14, 2013
  8. Jeff KingApr 14, 2013
  9. Junio C HamanoApr 15, 2013
  10. 3/3 commit-slab: introduce a macro to define a slab for new typeJunio C Hamano, Apr 14, 2013
  11. Jeff KingApr 14, 2013
  12. Junio C HamanoApr 15, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.