Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 41 additions & 30 deletions src/develop/pixelpipe_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@
#include "libs/colorpicker.h"
#include <stdlib.h>

static inline int _to_mb(size_t m)
{
return (int)((m + 0x80000lu) / 0x400lu / 0x400lu);
}

gboolean dt_dev_pixelpipe_cache_init(dt_dev_pixelpipe_t *pipe,
const int entries,
const size_t size,
Expand All @@ -36,7 +31,7 @@ gboolean dt_dev_pixelpipe_cache_init(dt_dev_pixelpipe_t *pipe,
dt_dev_pixelpipe_cache_t *cache = &pipe->cache;

cache->entries = entries;
cache->allmem = cache->hits = cache->calls = cache->tests = 0;
cache->allmem = cache->max_allmem = cache->hits = cache->calls = cache->tests = 0;
cache->memlimit = limit;

const size_t csize = sizeof(void *) + sizeof(size_t) + sizeof(dt_iop_buffer_dsc_t) + 2*sizeof(int32_t) + sizeof(uint64_t);
Expand Down Expand Up @@ -86,9 +81,10 @@ void dt_dev_pixelpipe_cache_cleanup(dt_dev_pixelpipe_t *pipe)

if(dt_pipe_is_full(pipe))
{
dt_print(DT_DEBUG_PIPE, "Session fullpipe cache report. hits/run=%.2f, hits/test=%.3f",
(double)(cache->hits) / fmax(1.0, pipe->runs),
(double)(cache->hits) / fmax(1.0, cache->tests));
dt_print(DT_DEBUG_PIPE, "Session fullpipe cache report. Maximum=%zuMB. hits/run=%.2f, hits/test=%.3f",
cache->max_allmem / DT_MEGA,
(double)(cache->hits) / fmax(1.0, pipe->runs),
(double)(cache->hits) / fmax(1.0, cache->tests));
}

for(int k = 0; k < cache->entries; k++)
Expand Down Expand Up @@ -332,7 +328,7 @@ gboolean dt_dev_pixelpipe_cache_get(dt_dev_pixelpipe_t *pipe,
{
dt_free_align(cache->data[cline]);
cache->allmem -= cache->size[cline];
cache->data[cline] = (void *)dt_alloc_aligned(size);
cache->data[cline] = (void *)dt_alloc_aligned(dt_round_size(size, 4096));
if(cache->data[cline])
{
cache->size[cline] = size;
Expand Down Expand Up @@ -368,7 +364,7 @@ gboolean dt_dev_pixelpipe_cache_get(dt_dev_pixelpipe_t *pipe,
return TRUE;
}

static void _mark_invalid_cacheline(const dt_dev_pixelpipe_cache_t *cache, const int k)
static inline void _mark_invalid_cacheline(const dt_dev_pixelpipe_cache_t *cache, const int k)
{
cache->hash[k] = DT_INVALID_HASH;
cache->ioporder[k] = 0;
Expand Down Expand Up @@ -438,36 +434,54 @@ static size_t _free_cacheline(dt_dev_pixelpipe_cache_t *cache, const int k)
cache->allmem -= removed;
cache->size[k] = 0;
cache->data[k] = NULL;
_mark_invalid_cacheline(cache, k);
cache->hash[k] = DT_INVALID_HASH;
cache->ioporder[k] = 0;
return removed;
}

static void _cline_stats(dt_dev_pixelpipe_cache_t *cache)
static inline int _used(const dt_dev_pixelpipe_cache_t *cache)
{
cache->lused = cache->linvalid = cache->limportant = 0;
int cnt = 0;
for(int k = DT_PIPECACHE_MIN; k < cache->entries; k++)
{
if(cache->data[k]) cache->lused++;
if(cache->data[k] && (cache->hash[k] == DT_INVALID_HASH)) cache->linvalid++;
if(cache->used[k] < 0) cache->limportant++;
}
if(cache->data[k] && cache->hash[k] != DT_INVALID_HASH) cnt++;
return cnt;
}
static inline int _important(const dt_dev_pixelpipe_cache_t *cache)
{
int cnt = 0;
for(int k = DT_PIPECACHE_MIN; k < cache->entries; k++)
if(cache->used[k] < 0 && cache->data[k] && cache->hash[k] != DT_INVALID_HASH) cnt++;
return cnt;
}
static inline int _invalid(const dt_dev_pixelpipe_cache_t *cache)
{
int cnt = 0;
for(int k = DT_PIPECACHE_MIN; k < cache->entries; k++)
if(cache->data[k] && cache->hash[k] == DT_INVALID_HASH) cnt++;
return cnt;
}

void dt_dev_pixelpipe_cache_checkmem(dt_dev_pixelpipe_t *pipe)
{
dt_dev_pixelpipe_cache_t *cache = &pipe->cache;

cache->max_allmem = MAX(cache->max_allmem, cache->allmem);
// we have pixelpipes like export & thumbnail that just use
// alternating buffers so no cleanup
if(cache->entries == DT_PIPECACHE_MIN) return;

// We always free cachelines marked as not valid
size_t freed = 0;
size_t freed_invalid = 0;
int free_cnt = 0;
int free_invalid_cnt = 0;
for(int k = DT_PIPECACHE_MIN; k < cache->entries; k++)
{
if((cache->hash[k] == DT_INVALID_HASH) && cache->data)
if(cache->hash[k] == DT_INVALID_HASH && cache->data[k])
{
freed_invalid += _free_cacheline(cache, k);
free_invalid_cnt++;
}
}

while(cache->memlimit && (cache->memlimit < cache->allmem))
Expand All @@ -476,24 +490,22 @@ void dt_dev_pixelpipe_cache_checkmem(dt_dev_pixelpipe_t *pipe)
if(k == 0) break;

freed += _free_cacheline(cache, k);
free_cnt++;
}

_cline_stats(cache);
dt_print_pipe(DT_DEBUG_PIPE | DT_DEBUG_MEMORY, "pipe cache check", pipe, NULL, DT_DEVICE_NONE, NULL, NULL,
"%i lines (important=%i, used=%i). Freed: invalid %iMB used %iMB. Using %iMB, limit=%iMB",
cache->entries, cache->limportant, cache->lused,
_to_mb(freed_invalid), _to_mb(freed), _to_mb(cache->allmem), _to_mb(cache->memlimit));
"Freed lines invalid=%i used=%i. Freed mem invalid %zuMB used %zuMB. Now %zuMB limit=%zuMB max=%zuMB",
free_invalid_cnt, free_cnt, freed_invalid/DT_MEGA, freed / DT_MEGA,
cache->allmem / DT_MEGA, cache->memlimit / DT_MEGA, cache->max_allmem / DT_MEGA);
}

void dt_dev_pixelpipe_cache_report(dt_dev_pixelpipe_t *pipe)
{
dt_dev_pixelpipe_cache_t *cache = &pipe->cache;

_cline_stats(cache);
dt_print_pipe(DT_DEBUG_PIPE | DT_DEBUG_MEMORY, "cache report", pipe, NULL, DT_DEVICE_NONE, NULL, NULL,
"%i lines (important=%i, used=%i, invalid=%i). Using %iMB, limit=%iMB. Hits/run=%.2f. Hits/test=%.3f",
cache->entries, cache->limportant, cache->lused, cache->linvalid,
_to_mb(cache->allmem), _to_mb(cache->memlimit),
"Lines=%i important=%i used=%i invalid=%i. Now=%zuMB limit=%zuMB max=%zuMB. Hits/run=%.2f. Hits/test=%.3f",
cache->entries, _important(cache), _used(cache), _invalid(cache),
cache->allmem / DT_MEGA, cache->memlimit / DT_MEGA, cache->max_allmem / DT_MEGA,
(double)(cache->hits) / fmax(1.0, pipe->runs),
(double)(cache->hits) / fmax(1.0, cache->tests));
}
Expand All @@ -503,4 +515,3 @@ void dt_dev_pixelpipe_cache_report(dt_dev_pixelpipe_t *pipe)
// vim: shiftwidth=2 expandtab tabstop=2 cindent
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
// clang-format on

8 changes: 3 additions & 5 deletions src/develop/pixelpipe_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ struct dt_iop_roi_t;
* implements a simple pixel cache suitable for caching float images
* corresponding to history items and zoom/pan settings in the develop module.
* correctness is secured via the hash so make sure everything is included here.
* No caching if cl_mem, instead copied cache buffers are used.
* No caching cl_mem, instead copied cache buffers are used.
*/
typedef struct dt_dev_pixelpipe_cache_t
{
int32_t entries;
size_t allmem;
size_t max_allmem;
size_t memlimit;
void **data;
size_t *size;
Expand All @@ -43,12 +44,9 @@ typedef struct dt_dev_pixelpipe_cache_t
int32_t *ioporder;
uint64_t calls;
int32_t lastline;
// profiling & stats:
// profiling
uint64_t tests;
uint64_t hits;
uint32_t lused;
uint32_t linvalid;
uint32_t limportant;
} dt_dev_pixelpipe_cache_t;

typedef enum dt_dev_pixelpipe_cache_test_t
Expand Down
Loading