[libcamera-devel] [PATCH v3 7/7] libcamera: V4L2BufferCache: Improve cache eviction strategy

Laurent Pinchart laurent.pinchart at ideasonboard.com
Thu Mar 5 00:38:21 CET 2020


Hi Niklas,

Thank you for the patch.

On Thu, Mar 05, 2020 at 12:22:46AM +0100, Niklas Söderlund wrote:
> The strategy used to find a free cache entry in the first implementation
> was not the smartest, it picked the first free entry. This lead to
> unwanted performance issues as the cache was not used as good as it
> could for imported buffers.
> 
> Improve this by adding a last usage sequence numer to the cache entries

s/numer/number/

> and change the eviction strategy to use the oldest free entry instead of
> the first one it finds.
> 
> Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> Reviewed-by: Naushir Patuck <naush at raspberrypi.com>
> ---
> * Changes since v2
> - Use a sequence number instead of timestamp to judge age of a cached
>   entry.
> ---
>  src/libcamera/include/v4l2_videodevice.h |  5 ++++-
>  src/libcamera/v4l2_videodevice.cpp       | 20 ++++++++++++--------
>  2 files changed, 16 insertions(+), 9 deletions(-)
> 
> diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h
> index 359b366454e4e782..993ebb3069c595bf 100644
> --- a/src/libcamera/include/v4l2_videodevice.h
> +++ b/src/libcamera/include/v4l2_videodevice.h
> @@ -10,6 +10,7 @@
>  #include <string>
>  #include <vector>
>  
> +#include <atomic>

This should go with the C++ headers above. So should the memory header.
You can fix this "while at it", no need for a separate patch ;-)

>  #include <linux/videodev2.h>
>  #include <memory>
>  
> @@ -120,11 +121,12 @@ private:
>  	{
>  	public:
>  		Entry();
> -		Entry(bool free, const FrameBuffer &buffer);
> +		Entry(bool free, uint64_t lastUsed, const FrameBuffer &buffer);
>  
>  		bool operator==(const FrameBuffer &buffer) const;
>  
>  		bool free;
> +		uint64_t lastUsed;
>  
>  	private:
>  		struct Plane {
> @@ -140,6 +142,7 @@ private:
>  		std::vector<Plane> planes_;
>  	};
>  
> +	std::atomic_uint64_t lastUsedCounter_;
>  	std::vector<Entry> cache_;
>  	/* \todo Expose the miss counter through an instrumentation API. */
>  	unsigned int missCounter_;
> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> index c495de85f26efe14..3043aebfe0588290 100644
> --- a/src/libcamera/v4l2_videodevice.cpp
> +++ b/src/libcamera/v4l2_videodevice.cpp
> @@ -162,7 +162,7 @@ LOG_DECLARE_CATEGORY(V4L2)
>   * buffer import, with buffers added to the cache as they are queued.
>   */
>  V4L2BufferCache::V4L2BufferCache(unsigned int numEntries)
> -	: missCounter_(0)
> +	: lastUsedCounter_(1), missCounter_(0)
>  {
>  	cache_.resize(numEntries);
>  }
> @@ -176,10 +176,11 @@ V4L2BufferCache::V4L2BufferCache(unsigned int numEntries)
>   * allocated.
>   */
>  V4L2BufferCache::V4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers)
> -	: missCounter_(0)
> +	: lastUsedCounter_(1), missCounter_(0)
>  {
>  	for (const std::unique_ptr<FrameBuffer> &buffer : buffers)
> -		cache_.emplace_back(true, buffer->planes());
> +		cache_.emplace_back(true, lastUsedCounter_.fetch_add(1),

I think the std::memory_order_acq_rel memory order should be enough for
this usage (same below). Should I be mean and ask you to confirm ? :-)

> +				    buffer->planes());
>  }
>  
>  V4L2BufferCache::~V4L2BufferCache()
> @@ -205,6 +206,7 @@ int V4L2BufferCache::get(const FrameBuffer &buffer)
>  {
>  	bool hit = false;
>  	int use = -1;
> +	uint64_t oldest = UINT32_MAX;

UINT64_MAX ?

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

>  
>  	for (unsigned int index = 0; index < cache_.size(); index++) {
>  		const Entry &entry = cache_[index];
> @@ -219,8 +221,10 @@ int V4L2BufferCache::get(const FrameBuffer &buffer)
>  			break;
>  		}
>  
> -		if (use < 0)
> +		if (entry.lastUsed < oldest) {
>  			use = index;
> +			oldest = entry.lastUsed;
> +		}
>  	}
>  
>  	if (!hit)
> @@ -229,7 +233,7 @@ int V4L2BufferCache::get(const FrameBuffer &buffer)
>  	if (use < 0)
>  		return -ENOENT;
>  
> -	cache_[use] = Entry(false, buffer);
> +	cache_[use] = Entry(false, lastUsedCounter_.fetch_add(1), buffer);
>  
>  	return use;
>  }
> @@ -245,12 +249,12 @@ void V4L2BufferCache::put(unsigned int index)
>  }
>  
>  V4L2BufferCache::Entry::Entry()
> -	: free(true)
> +	: free(true), lastUsed(0)
>  {
>  }
>  
> -V4L2BufferCache::Entry::Entry(bool free, const FrameBuffer &buffer)
> -	: free(free)
> +V4L2BufferCache::Entry::Entry(bool free, uint64_t lastUsed, const FrameBuffer &buffer)
> +	: free(free), lastUsed(lastUsed)
>  {
>  	for (const FrameBuffer::Plane &plane : buffer.planes())
>  		planes_.emplace_back(plane);

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list