On Thu, 2017-05-04 at 07:49 -0700, Jason Ekstrand wrote:
> On Thu, May 4, 2017 at 1:00 AM, Juan A. Suarez Romero <jasua...@igalia.com> 
> wrote:
> > On Wed, 2017-04-26 at 07:35 -0700, Jason Ekstrand wrote:
> > > Previously, the maximum size of a state that could be allocated from a
> > > state pool was a block.  However, this has caused us various issues
> > > particularly with shaders which are potentially very large.  We've also
> > > hit issues with render passes with a large number of attachments when we
> > > go to allocate the block of surface state.  This effectively removes the
> > > restriction on the maximum size of a single state.  (There's still a
> > > limit of 1MB imposed by a fixed-length bucket array.)
> > >
> > > For states larger than the block size, we just grab a large block off of
> > > the block pool rather than sub-allocating.  When we go to allocate some
> > > chunk of state and the current bucket does not have state, we try to
> > > pull a chunk from some larger bucket and split it up.  This should
> > > improve memory usage if a client occasionally allocates a large block of
> > > state.
> > >
> > > This commit is inspired by some similar work done by Juan A. Suarez
> > > Romero <jasua...@igalia.com>.
> > > ---
> > >  src/intel/vulkan/anv_allocator.c | 43 
> > >++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 43 insertions(+)
> > >
> > > diff --git a/src/intel/vulkan/anv_allocator.c 
> > > b/src/intel/vulkan/anv_allocator.c
> > > index 7a687b7..68c389c 100644
> > > --- a/src/intel/vulkan/anv_allocator.c
> > > +++ b/src/intel/vulkan/anv_allocator.c
> > > @@ -650,6 +650,12 @@ anv_fixed_size_state_pool_alloc_new(struct 
> > > anv_fixed_size_state_pool *pool,
> > >     struct anv_block_state block, old, new;
> > >     uint32_t offset;
> > >
> > > +   /* If our state is large, we don't need any sub-allocation from a 
> > > block.
> > > +    * Instead, we just grab whole (potentially large) blocks.
> > > +    */
> > > +   if (state_size >= block_size)
> > > +      return anv_block_pool_alloc(block_pool, state_size);
> > > +
> > >   restart:
> > >     block.u64 = __sync_fetch_and_add(&pool->block.u64, state_size);
> > >
> > > @@ -702,6 +708,43 @@ anv_state_pool_alloc_no_vg(struct anv_state_pool 
> > > *pool,
> > >        goto done;
> > >     }
> > >
> > > +   /* Try to grab a chunk from some larger bucket and split it up */
> > > +   for (unsigned b = bucket + 1; b < ANV_STATE_BUCKETS; b++) {
> > > +      int32_t chunk_offset;
> > > +      if (anv_free_list_pop(&pool->buckets[b].free_list,
> > > +                            &pool->block_pool.map, &chunk_offset)) {
> > > +         unsigned chunk_size = anv_state_pool_get_bucket_size(b);
> > > +
> > > +         if (chunk_size > pool->block_size &&
> > > +             state.alloc_size < pool->block_size) {
> > > +            assert(chunk_size % pool->block_size == 0);
> > > +            /* We don't want to split giant chunks into tiny chunks.  
> > > Instead,
> > > +             * break anything bigger than a block into block-sized 
> > > chunks and
> > > +             * then break it down into bucket-sized chunks from there.  
> > > Return
> > > +             * all but the first block of the chunk to the block bucket.
> > > +             */
> > > +            const uint32_t block_bucket =
> > > +               anv_state_pool_get_bucket(pool->block_size);
> > > +            anv_free_list_push(&pool->buckets[block_bucket].free_list,
> > > +                               pool->block_pool.map,
> > > +                               chunk_offset + pool->block_size,
> > > +                               pool->block_size,
> > > +                               (chunk_size / pool->block_size) - 1);
> > > +            chunk_size = pool->block_size;
> > > +         }
> > > +
> > > +         assert(chunk_size % state.alloc_size == 0);
> > > +         anv_free_list_push(&pool->buckets[bucket].free_list,
> > > +                            pool->block_pool.map,
> > > +                            chunk_offset + state.alloc_size,
> > > +                            state.alloc_size,
> > > +                            (chunk_size / state.alloc_size) - 1);
> > > +
> > > +         state.offset = chunk_offset;
> > > +         goto done;
> > > +      }
> > 
> > 
> > Wouldn't it better to split the bucket just in two parts, one to be
> > used for our request, and the other with the available free space, but
> > in on single bucket, instead of splitting it in various parts?
> > 
> > This way, if we later get a new request that can potentially required
> > the full (or part of) free single bucket we can assign it entirely (or
> > splitting it again).
> 
> Would you mind rephrasing that?  I'm not really sure what you mean.  There 
> are two other options in my mind:

After re-thinking, I think what I wanted to do is a non-sense.

In the example below, I was thinking on using 16B out of 2MB for the
request, and put the remaining space (2MB-16B) in *one* bucket. Which,
of course, is a non sense.

> 
>  1. Fully split the chunk.  This would mean that allocating a 16B state could 
> potentially split a 2MB chunk into 512K smaller chunks.  I'm trying to avoid 
> that quantity of fragmentation.
> 
>  2. Scatter the chunk through the buckets.  If you got a 2MB chunk, it would 
> generate one of each: 2MB, 1MB, 512KB, 256KB, ..., 128B, 128B, 64B, and 32B 
> and two 16B states.  The issue here is that you end up doing log2(chunk_size 
> / state_size) atomics and it's very likely that you'll allocate more 16B 
> states soon and every other one will have to go at least one bucket up.  
> Under the assumption that we tend to allocate identically-sized states, I 
> think this is likely to perform worse than splitting a block_size thing into 
> into block_size / state_size many chunks.
> 
> What I did is an attempt to split the difference by splitting it at two 
> levels rather than one or all.
> 


I see now. Thanks for the explanation! 

Reviewed-by: Juan A. Suarez Romero <jasua...@igalia.com>


> --Jason
>  
> >         J.A.
> > 
> > 
> > 
> > > +   }
> > > +
> > >     state.offset = 
> > >anv_fixed_size_state_pool_alloc_new(&pool->buckets[bucket],
> > >                                                        &pool->block_pool,
> > >                                                        state.alloc_size,
> > _______________________________________________
> > mesa-dev mailing list
> > mesa-dev@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/mesa-dev
> > 
> 
> 
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to