Skip to content
Snippets Groups Projects
Select Git revision
  • pu
  • passt default
  • master
  • todo
  • next
  • maint
  • v2.8.0-rc1
  • v2.8.0-rc0
  • v2.7.2
  • v2.7.1
  • v2.7.0
  • v2.6.5
  • v2.7.0-rc3
  • v2.7.0-rc2
  • v2.7.0-rc1
  • v2.7.0-rc0
  • v2.6.4
  • v2.6.3
  • v2.6.2
  • v2.6.1
  • v2.3.10
  • v2.5.4
  • v2.4.10
  • v2.6.0
  • v2.6.0-rc3
  • v2.5.3
26 results

commit-slab.h

Blame
    • Junio C Hamano's avatar
      720e20eb
      Merge branch 'jc/commit-slab' · 720e20eb
      Junio C Hamano authored
      Memory use reduction when commit-slab facility is used to annotate
      sparsely (which is not recommended in the first place).
      
      * jc/commit-slab:
        commit-slab: introduce slabname##_peek() function
      720e20eb
      History
      Merge branch 'jc/commit-slab'
      Junio C Hamano authored
      Memory use reduction when commit-slab facility is used to annotate
      sparsely (which is not recommended in the first place).
      
      * jc/commit-slab:
        commit-slab: introduce slabname##_peek() function
    commit-slab.h 4.76 KiB
    #ifndef COMMIT_SLAB_H
    #define COMMIT_SLAB_H
    
    /*
     * define_commit_slab(slabname, elemtype) creates boilerplate code to define
     * a new struct (struct slabname) that is used to associate a piece of data
     * of elemtype to commits, and a few functions to use that struct.
     *
     * After including this header file, using:
     *
     * define_commit_slab(indegee, int);
     *
     * will let you call the following functions:
     *
     * - int *indegree_at(struct indegree *, struct commit *);
     *
     *   This function locates the data associated with the given commit in
     *   the indegree slab, and returns the pointer to it.  The location to
     *   store the data is allocated as necessary.
     *
     * - int *indegree_peek(struct indegree *, struct commit *);
     *
     *   This function is similar to indegree_at(), but it will return NULL
     *   until a call to indegree_at() was made for the commit.
     *
     * - void init_indegree(struct indegree *);
     *   void init_indegree_with_stride(struct indegree *, int);
     *
     *   Initializes the indegree slab that associates an array of integers
     *   to each commit. 'stride' specifies how big each array is.  The slab
     *   that is initialized by the variant without "_with_stride" associates
     *   each commit with an array of one integer.
     *
     * - void clear_indegree(struct indegree *);
     *
     *   Empties the slab.  The slab can be reused with the same stride
     *   without calling init_indegree() again or can be reconfigured to a
     *   different stride by calling init_indegree_with_stride().
     *
     *   Call this function before the slab falls out of scope to avoid
     *   leaking memory.
     */
    
    /* allocate ~512kB at once, allowing for malloc overhead */
    #ifndef COMMIT_SLAB_SIZE
    #define COMMIT_SLAB_SIZE (512*1024-32)
    #endif
    
    #define MAYBE_UNUSED __attribute__((__unused__))
    
    #define define_commit_slab(slabname, elemtype) 				\
    									\
    struct slabname {							\
    	unsigned slab_size;						\
    	unsigned stride;						\
    	unsigned slab_count;						\
    	elemtype **slab;						\
    };									\
    static int stat_ ##slabname## realloc;					\
    									\
    static MAYBE_UNUSED void init_ ##slabname## _with_stride(struct slabname *s, \
    						   unsigned stride)	\
    {									\
    	unsigned int elem_size;						\
    	if (!stride)							\
    		stride = 1;						\
    	s->stride = stride;						\
    	elem_size = sizeof(elemtype) * stride;				\
    	s->slab_size = COMMIT_SLAB_SIZE / elem_size;			\
    	s->slab_count = 0;						\
    	s->slab = NULL;							\
    }									\
    									\
    static MAYBE_UNUSED void init_ ##slabname(struct slabname *s)		\
    {									\
    	init_ ##slabname## _with_stride(s, 1);				\
    }									\
    									\
    static MAYBE_UNUSED void clear_ ##slabname(struct slabname *s)		\
    {									\
    	int i;								\
    	for (i = 0; i < s->slab_count; i++)				\
    		free(s->slab[i]);					\
    	s->slab_count = 0;						\
    	free(s->slab);							\
    	s->slab = NULL;							\
    }									\
    									\
    static MAYBE_UNUSED elemtype *slabname## _at_peek(struct slabname *s,	\
    						  const struct commit *c, \
    						  int add_if_missing)   \
    {									\
    	int nth_slab, nth_slot;						\
    									\
    	nth_slab = c->index / s->slab_size;				\
    	nth_slot = c->index % s->slab_size;				\
    									\
    	if (s->slab_count <= nth_slab) {				\
    		int i;							\
    		if (!add_if_missing)					\
    			return NULL;					\
    		REALLOC_ARRAY(s->slab, nth_slab + 1);			\
    		stat_ ##slabname## realloc++;				\
    		for (i = s->slab_count; i <= nth_slab; i++)		\
    			s->slab[i] = NULL;				\
    		s->slab_count = nth_slab + 1;				\
    	}								\
    	if (!s->slab[nth_slab]) {					\
    		if (!add_if_missing)					\
    			return NULL;					\
    		s->slab[nth_slab] = xcalloc(s->slab_size,		\
    					    sizeof(**s->slab) * s->stride);		\
    	}								\
    	return &s->slab[nth_slab][nth_slot * s->stride];		\
    }									\
    									\
    static MAYBE_UNUSED elemtype *slabname## _at(struct slabname *s,	\
    					     const struct commit *c)	\
    {									\
    	return slabname##_at_peek(s, c, 1);				\
    }									\
    									\
    static MAYBE_UNUSED elemtype *slabname## _peek(struct slabname *s,	\
    					     const struct commit *c)	\
    {									\
    	return slabname##_at_peek(s, c, 0);				\
    }									\
    									\
    static int stat_ ##slabname## realloc
    
    /*
     * Note that this seemingly redundant second declaration is required
     * to allow a terminating semicolon, which makes instantiations look
     * like function declarations.  I.e., the expansion of
     *
     *    define_commit_slab(indegree, int);
     *
     * ends in 'static int stat_indegreerealloc;'.  This would otherwise
     * be a syntax error according (at least) to ISO C.  It's hard to
     * catch because GCC silently parses it by default.
     */
    
    /*
     * Statically initialize a commit slab named "var". Note that this
     * evaluates "stride" multiple times! Example:
     *
     *   struct indegree indegrees = COMMIT_SLAB_INIT(1, indegrees);
     *
     */
    #define COMMIT_SLAB_INIT(stride, var) { \
    	COMMIT_SLAB_SIZE / sizeof(**((var).slab)) / (stride), \
    	(stride), 0, NULL \
    }
    
    #endif /* COMMIT_SLAB_H */