Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
pixelpipe_cache.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel
3 Copyright (C) 2025 - Aurélien PIERRE
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with darktable. If not, see <http://www.gnu.org/licenses/>.
17*/
18
20#include "common/darktable.h"
21#include "common/debug.h"
22#include "develop/format.h"
24#include <glib.h>
25#include <stdlib.h>
26
27
29{
30 uint64_t hash; // unique identifier of the entry
31 void *data; // buffer holding pixels... or anything else
32 size_t size; // size of the data buffer
33 dt_iop_buffer_dsc_t dsc; // metadata of the data buffer
34 int64_t age; // timestamp of creation. Oldest entry will be the first freed if it's not locked
35 char *name; // name of the cache entry, for debugging
36 int id; // id of the pipeline owning this entry. Used when flushing, a pipe can only flush its own.
37 dt_atomic_int refcount; // reference count for the cache entry, to avoid freeing it while still in use
38 dt_pthread_rwlock_t lock; // read/write lock to avoid threads conflicts
39 gboolean auto_destroy; // TRUE for auto-destruction the next time it's used. Used for short-lived entries (transient states).
41
42
44 dt_pixel_cache_entry_t *cache_entry);
45
47{
48 return (dt_pixel_cache_entry_t *)g_hash_table_lookup(cache->entries, GINT_TO_POINTER(hash));
49}
50
51
59
60
62{
63 return cache_entry->size / (1024 * 1024);
64}
65
66
67void dt_pixel_cache_message(dt_pixel_cache_entry_t *cache_entry, const char *message, gboolean verbose)
68{
69 if(!(darktable.unmuted & DT_DEBUG_PIPE)) return;
70 if(verbose && !(darktable.unmuted & DT_DEBUG_VERBOSE)) return;
71 dt_print(DT_DEBUG_PIPE, "[pixelpipe] cache entry %lu: %s (%lu MiB - age %li) %s\n", cache_entry->hash,
72 cache_entry->name, dt_pixel_cache_get_size(cache_entry), cache_entry->age, message);
73}
74
75
76// remove the cache entry with the given hash and update the cache memory usage
77// WARNING: not internally thread-safe, protect its calls with mutex lock
78// return 0 on success, 1 on error
79int _non_thread_safe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const gboolean force,
80 dt_pixel_cache_entry_t *cache_entry)
81{
82 if(cache_entry == NULL)
83 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
84
85 if(cache_entry)
86 {
87 // Returns 1 if the lock is captured by another thread
88 // 0 if WE capture the lock, and then need to release it
89 gboolean locked = dt_pthread_rwlock_trywrlock(&cache_entry->lock);
90 if(!locked) dt_pthread_rwlock_unlock(&cache_entry->lock);
91 gboolean used = dt_atomic_get_int(&cache_entry->refcount) > 0;
92
93 if((!used || force) && !locked)
94 {
95 cache->current_memory -= cache_entry->size;
96 g_hash_table_remove(cache->entries, GINT_TO_POINTER(hash));
97 return 0;
98 }
99 else if(used)
100 dt_pixel_cache_message(cache_entry, "cannot remove: used", TRUE);
101 else if(locked)
102 dt_pixel_cache_message(cache_entry, "cannot remove: locked", TRUE);
103 }
104 else
105 {
106 dt_print(DT_DEBUG_PIPE, "[pixelpipe] cache entry %lu not found, will not be removed\n", hash);
107 }
108 return 1;
109}
110
111
112int dt_dev_pixelpipe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const gboolean force,
113 dt_pixel_cache_entry_t *cache_entry)
114{
116 int error = _non_thread_safe_cache_remove(cache, hash, force, cache_entry);
118 return error;
119}
120
127
128
129// find the cache entry hash with the oldest use
130void _cache_get_oldest(gpointer key, gpointer value, gpointer user_data)
131{
132 dt_pixel_cache_entry_t *cache_entry = (dt_pixel_cache_entry_t *)value;
133 _cache_lru_t *lru = (_cache_lru_t *)user_data;
134
135 // Don't remove LRU entries that are still in use
136 // NOTE: with all the killswitches mechanisms and safety measures,
137 // we might have more things decreasing refcount than increasing it.
138 // It's no big deal though, as long as the (final output) backbuf
139 // is checked for NULL and not reused if pipeline is DIRTY.
140 if(cache_entry->age < lru->max_age)
141 {
142 // Returns 1 if the lock is captured by another thread
143 // 0 if WE capture the lock, and then need to release it
144 gboolean locked = dt_pthread_rwlock_trywrlock(&cache_entry->lock);
145 if(!locked) dt_pthread_rwlock_unlock(&cache_entry->lock);
146 gboolean used = dt_atomic_get_int(&cache_entry->refcount) > 0;
147
148 if(!locked && !used)
149 {
150 lru->max_age = cache_entry->age;
151 lru->hash = cache_entry->hash;
152 lru->cache_entry = cache_entry;
153 dt_pixel_cache_message(cache_entry, "candidate for deletion", TRUE);
154 }
155 else if(used)
156 dt_pixel_cache_message(cache_entry, "cannot be deleted: used", TRUE);
157 else if(locked)
158 dt_pixel_cache_message(cache_entry, "cannot be deleted: locked", TRUE);
159 }
160}
161
162
163// remove the least used cache entry
164// return 0 on success, 1 on error
165// error is : we couldn't find a candidate for deletion because all entries are either locked or in use
166// or we found one but failed to remove it.
168{
169 _cache_lru_t *lru = (_cache_lru_t *)malloc(sizeof(_cache_lru_t));
170 lru->max_age = g_get_monotonic_time();
171 lru->hash = 0;
172 lru->cache_entry = NULL;
173 int error = 1;
174 g_hash_table_foreach(cache->entries, _cache_get_oldest, lru);
175
176 if(lru->hash > 0)
178 else
179 dt_print(DT_DEBUG_PIPE, "[pixelpipe] couldn't remove LRU, %i items and all are used\n", g_hash_table_size(cache->entries));
180
181 free(lru);
182 return error;
183}
184
185// return 0 on success 1 on error
193
194// WARNING: not thread-safe, protect its calls with mutex lock
196 const dt_iop_buffer_dsc_t dsc, const char *name, const int id,
198{
199 // Dynamically update the max cache size depending on remaining free memory on system
200 const size_t remaining_mem = dt_get_available_mem();
201 const size_t safety_margin = 4 * dt_get_singlebuffer_mem();
202 if(remaining_mem < safety_margin)
203 {
204 cache->max_memory
205 = MIN(MAX((int64_t)remaining_mem - (int64_t)safety_margin, (int64_t)2 * dt_get_singlebuffer_mem()),
206 remaining_mem);
207 fprintf(stdout, "new pipeline cache size : %lu MiB\n", cache->max_memory / (1024 * 1024));
208 if(cache->max_memory == 2 * dt_get_singlebuffer_mem())
209 dt_control_log(_("Your system RAM is nearly saturated.\n"
210 "Processing full-resolution images may not "
211 "possible anymore.\n"));
212 }
213
214 // Free up space if needed to match the max memory limit
215 // If error, all entries are currently locked or in use, so we cannot free space to allocate a new entry.
216 int error = 0;
217 while(cache->current_memory + size > cache->max_memory && g_hash_table_size(cache->entries) > 0 && !error)
219
220 if(cache->current_memory + size > cache->max_memory)
221 {
222 dt_print(DT_DEBUG_PIPE, "[pixelpipe] cache is full, cannot allocate new entry %lu (%s)\n", hash, name);
223 return NULL; // not enough memory
224 }
225
227 if(!cache_entry) return NULL;
228
229 // allocate the data buffer
230 cache_entry->data = dt_alloc_align(size);
231
232 // if allocation failed, remove the least recently used cache entry, then try again
233 while(cache_entry->data == NULL && g_hash_table_size(cache->entries) > 0)
234 {
236 cache_entry->data = dt_alloc_align(size);
237 }
238
239 if(!cache_entry->data)
240 {
241 free(cache_entry);
242 return NULL;
243 }
244
245 cache_entry->size = size;
246 cache_entry->age = 0;
247 cache_entry->dsc = dsc;
248 cache_entry->hash = hash;
249 cache_entry->id = id;
250 cache_entry->name = g_strdup(name);
251 cache_entry->refcount = 0;
252 cache_entry->auto_destroy = FALSE;
253 dt_pthread_rwlock_init(&cache_entry->lock, NULL);
254
255 g_hash_table_insert(cache->entries, GINT_TO_POINTER(hash), cache_entry);
256 cache->current_memory += size;
257
258 return cache_entry;
259}
260
261
263{
264 if(!cache_entry) return;
265 dt_pixel_cache_message(cache_entry, "freed", FALSE);
266 dt_free_align(cache_entry->data);
267 cache_entry->data = NULL;
268 dt_pthread_rwlock_destroy(&cache_entry->lock);
269 g_free(cache_entry->name);
270 free(cache_entry);
271}
272
273
275{
277 dt_pthread_mutex_init(&cache->lock, NULL);
278 cache->entries = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)_free_cache_entry);
279 cache->max_memory = max_memory;
280 cache->current_memory = 0;
281 cache->queries = cache->hits = 0;
282 return cache;
283}
284
285
287{
288 if(!cache) return;
290 g_hash_table_destroy(cache->entries);
291 cache->entries = NULL;
292}
293
294
296 const size_t size, const char *name, const int id,
297 void **data, dt_iop_buffer_dsc_t **dsc,
299{
301
302 cache->queries++;
303
304 // Find the cache entry for this hash, if any
306 gboolean cache_entry_found = (cache_entry != NULL);
307
308 if(cache_entry)
309 cache->hits++;
310 else
311 cache_entry = dt_pixel_cache_new_entry(hash, size, **dsc, name, id, cache);
312
313 if(cache_entry)
314 {
315 cache_entry->age = g_get_monotonic_time(); // this is the MRU entry
316 *data = cache_entry->data;
317 *dsc = &cache_entry->dsc;
318 dt_pixel_cache_message(cache_entry, (cache_entry_found) ? "found" : "created", FALSE);
319
320 // This will become the input for the next module, lock it until next module process ends
322 }
323 else
324 {
325 // Don't write on *dsc and *data here
326 dt_print(DT_DEBUG_PIPE, "couldn't allocate new cache entry %lu\n", hash);
327 }
328
329 if(entry) *entry = cache_entry;
330
332 return !cache_entry_found;
333}
334
336 void **data, dt_iop_buffer_dsc_t **dsc, dt_pixel_cache_entry_t **entry)
337{
338 // Find the cache entry for this hash, if any
340 cache->queries++;
342 if(cache_entry) cache->hits++;
343
344 if(cache_entry)
345 {
346 cache_entry->age = g_get_monotonic_time(); // this is the MRU entry
347 *data = cache_entry->data;
348 *dsc = &cache_entry->dsc;
349 dt_pixel_cache_message(cache_entry, "found", FALSE);
350
351 // This will become the input for the next module, lock it until next module process ends
353 }
354
355 if(entry) *entry = cache_entry;
356
358 return cache_entry != NULL;
359}
360
361
362gboolean _for_each_remove(gpointer key, gpointer value, gpointer user_data)
363{
364 dt_pixel_cache_entry_t *cache_entry = (dt_pixel_cache_entry_t *)value;
365 const int id = GPOINTER_TO_INT(user_data);
366
367 // Returns 1 if the lock is captured by another thread
368 // 0 if WE capture the lock, and then need to release it
369 gboolean locked = dt_pthread_rwlock_trywrlock(&cache_entry->lock);
370 if(!locked) dt_pthread_rwlock_unlock(&cache_entry->lock);
371 gboolean used = dt_atomic_get_int(&cache_entry->refcount) > 0;
372
373 return (cache_entry->id == id || id == -1) && !used && !locked;
374}
375
377{
379 g_hash_table_foreach_remove(cache->entries, _for_each_remove, GINT_TO_POINTER(id));
380 cache->current_memory = 0;
382}
383
389
390
392{
393 GHashTableIter iter;
394 gpointer key, value;
395 uint64_t hash = 0;
396 if(entry) *entry = NULL;
397
398 g_hash_table_iter_init(&iter, cache->entries);
399 while(g_hash_table_iter_next(&iter, &key, &value))
400 {
401 dt_pixel_cache_entry_t *cache_entry = (dt_pixel_cache_entry_t *)value;
402 if(cache_entry->data == data)
403 {
404 hash = cache_entry->hash;
405 if(entry) *entry = cache_entry;
406 break;
407 }
408 }
409
410 return hash;
411}
412
413
421
422
424{
425 dt_pixel_cache_entry_t *cache_entry;
427
428 _non_thread_safe_cache_get_hash_data(cache, data, &cache_entry);
429 if(cache_entry)
430 {
431 dt_pthread_rwlock_rdlock(&cache_entry->lock);
432 dt_pixel_cache_message(cache_entry, "read lock", TRUE);
433 }
434
436 return cache_entry;
437}
438
439
441 dt_pixel_cache_entry_t *cache_entry)
442{
443 if(cache_entry == NULL)
444 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
445
446 if(cache_entry)
447 {
448 if(lock)
449 {
450 dt_atomic_add_int(&cache_entry->refcount, 1);
451 dt_pixel_cache_message(cache_entry, "ref count ++", TRUE);
452 }
453 else
454 {
455 dt_atomic_sub_int(&cache_entry->refcount, 1);
456 dt_pixel_cache_message(cache_entry, "ref count --", TRUE);
457 }
458 }
459}
460
461
463 dt_pixel_cache_entry_t *cache_entry)
464{
466 _non_thread_safe_cache_ref_count_entry(cache, hash, lock, cache_entry);
468}
469
470
472 dt_pixel_cache_entry_t *cache_entry)
473{
475 if(cache_entry == NULL)
476 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
477
478 if(cache_entry)
479 {
480 if(lock)
481 {
482 dt_pthread_rwlock_wrlock(&cache_entry->lock);
483 dt_pixel_cache_message(cache_entry, "write lock", TRUE);
484 }
485 else
486 {
487 dt_pthread_rwlock_unlock(&cache_entry->lock);
488 dt_pixel_cache_message(cache_entry, "write unlock", TRUE);
489 }
490 }
492}
493
494
496 dt_pixel_cache_entry_t *cache_entry)
497{
499 if(cache_entry == NULL)
500 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
501
502 if(cache_entry)
503 {
504 if(lock)
505 {
506 dt_pthread_rwlock_rdlock(&cache_entry->lock);
507 dt_pixel_cache_message(cache_entry, "read lock", TRUE);
508 }
509 else
510 {
511 dt_pthread_rwlock_unlock(&cache_entry->lock);
512 dt_pixel_cache_message(cache_entry, "read unlock", TRUE);
513 }
514 }
516}
517
518
520 dt_pixel_cache_entry_t *cache_entry)
521{
523 if(cache_entry == NULL)
524 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
525
526 if(cache_entry) cache_entry->auto_destroy = TRUE;
528}
529
530
532 dt_pixel_cache_entry_t *cache_entry)
533{
535 if(cache_entry == NULL)
536 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
537
538 if(cache_entry && cache_entry->auto_destroy && id == cache_entry->id)
539 {
540 cache->current_memory -= cache_entry->size;
541 g_hash_table_remove(cache->entries, GINT_TO_POINTER(hash));
542 }
544}
545
546
548{
549 if(!(darktable.unmuted & DT_DEBUG_PIPE)) return;
550
551 dt_print(DT_DEBUG_PIPE, "[pixelpipe] cache hit rate so far: %.3f%% - size: %lu MiB over %lu MiB - %i items\n", 100. * (cache->hits) / (float)cache->queries, cache->current_memory / (1024 * 1024), cache->max_memory / (1024 * 1024), g_hash_table_size(cache->entries));
552}
553
554// clang-format off
555// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
556// vim: shiftwidth=2 expandtab tabstop=2 cindent
557// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
558// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:191
#define TRUE
Definition ashift_lsd.c:151
#define FALSE
Definition ashift_lsd.c:147
int dt_atomic_get_int(dt_atomic_int *var)
Definition atomic.h:46
int dt_atomic_sub_int(dt_atomic_int *var, int decr)
Definition atomic.h:48
int dt_atomic_add_int(dt_atomic_int *var, int incr)
Definition atomic.h:47
atomic_int dt_atomic_int
Definition atomic.h:44
char * key
Definition common/metadata.c:40
char * name
Definition common/metadata.c:41
void dt_control_log(const char *msg,...)
Definition control.c:424
darktable_t darktable
Definition darktable.c:111
size_t dt_get_singlebuffer_mem()
Definition darktable.c:1548
size_t dt_get_available_mem()
Definition darktable.c:1535
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1395
@ DT_DEBUG_PIPE
Definition darktable.h:497
@ DT_DEBUG_VERBOSE
Definition darktable.h:499
#define dt_free_align(A)
Definition darktable.h:334
#define dt_pthread_rwlock_destroy
Definition dtpthread.h:338
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:321
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:306
#define dt_pthread_rwlock_wrlock
Definition dtpthread.h:341
#define dt_pthread_rwlock_t
Definition dtpthread.h:336
#define dt_pthread_rwlock_trywrlock
Definition dtpthread.h:343
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:326
#define dt_pthread_rwlock_init
Definition dtpthread.h:337
#define dt_pthread_rwlock_unlock
Definition dtpthread.h:339
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:311
#define dt_pthread_rwlock_rdlock
Definition dtpthread.h:340
size_t size
Definition mipmap_cache.c:3
int dt_dev_pixelpipe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const gboolean force, dt_pixel_cache_entry_t *cache_entry)
Arbitrarily remove the cache entry matching hash. Entries having a reference count > 0 (inter-thread ...
Definition pixelpipe_cache.c:112
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
Definition pixelpipe_cache.c:462
size_t dt_pixel_cache_get_size(dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_cache.c:61
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Definition pixelpipe_cache.c:495
void dt_dev_pixelpipe_cache_cleanup(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:286
void _cache_get_oldest(gpointer key, gpointer value, gpointer user_data)
Definition pixelpipe_cache.c:130
dt_dev_pixelpipe_cache_t * dt_dev_pixelpipe_cache_init(size_t max_memory)
Definition pixelpipe_cache.c:274
void dt_dev_pixelpipe_cache_wrlock_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
Definition pixelpipe_cache.c:471
void dt_dev_pixelpipe_cache_print(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:547
void dt_dev_pixelpipe_cache_flush(dt_dev_pixelpipe_cache_t *cache, const int id)
Remove cache lines matching id. Entries locked in read/write or having reference count greater than 0...
Definition pixelpipe_cache.c:376
void dt_dev_pixel_pipe_cache_auto_destroy_apply(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const int id, dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_cache.c:531
static int _non_thread_safe_pixel_pipe_cache_remove_lru(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:167
uint64_t dt_dev_pixelpipe_cache_get_hash_data(dt_dev_pixelpipe_cache_t *cache, void *data, dt_pixel_cache_entry_t **entry)
Find the hash of the cache entry holding the buffer data.
Definition pixelpipe_cache.c:414
static dt_pixel_cache_entry_t * dt_pixel_cache_new_entry(const uint64_t hash, const size_t size, const dt_iop_buffer_dsc_t dsc, const char *name, const int id, dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:195
void dt_dev_pixelpipe_cache_flag_auto_destroy(dt_dev_pixelpipe_cache_t *cache, uint64_t hash, dt_pixel_cache_entry_t *cache_entry)
Flag the cache entry matching hash as "auto_destroy". This is useful for short-lived/disposable cache...
Definition pixelpipe_cache.c:519
int dt_dev_pixel_pipe_cache_remove_lru(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:186
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_get_entry_from_data(dt_dev_pixelpipe_cache_t *cache, void *data)
Return a reference to the cache entry holding the data buffer, or NULL if not found.
Definition pixelpipe_cache.c:423
int dt_dev_pixelpipe_cache_get_existing(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data, dt_iop_buffer_dsc_t **dsc, dt_pixel_cache_entry_t **entry)
Get an existing cache line from the cache. This is similar to dt_dev_pixelpipe_cache_get,...
Definition pixelpipe_cache.c:335
static void _free_cache_entry(dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_cache.c:262
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_get_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash)
Get an internal reference to the cache entry matching hash. If you are going to access this entry mor...
Definition pixelpipe_cache.c:52
dt_pixel_cache_entry_t * _non_threadsafe_cache_get_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash)
Definition pixelpipe_cache.c:46
void _non_thread_safe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_cache.c:440
void dt_pixel_cache_message(dt_pixel_cache_entry_t *cache_entry, const char *message, gboolean verbose)
Definition pixelpipe_cache.c:67
int _non_thread_safe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const gboolean force, dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_cache.c:79
gboolean _for_each_remove(gpointer key, gpointer value, gpointer user_data)
Definition pixelpipe_cache.c:362
uint64_t _non_thread_safe_cache_get_hash_data(dt_dev_pixelpipe_cache_t *cache, void *data, dt_pixel_cache_entry_t **entry)
Definition pixelpipe_cache.c:391
int dt_dev_pixelpipe_cache_get(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const size_t size, const char *name, const int id, void **data, dt_iop_buffer_dsc_t **dsc, dt_pixel_cache_entry_t **entry)
Get a cache line from the cache. This internally increases the reference count, so you have to manual...
Definition pixelpipe_cache.c:295
Pixelpipe cache for storing intermediate results in the pixelpipe.
unsigned __int64 uint64_t
Definition strptime.c:71
Definition pixelpipe_cache.c:385
size_t size
Definition pixelpipe_cache.c:387
void * data
Definition pixelpipe_cache.c:386
Definition pixelpipe_cache.c:122
int64_t max_age
Definition pixelpipe_cache.c:123
dt_pixel_cache_entry_t * cache_entry
Definition pixelpipe_cache.c:125
uint64_t hash
Definition pixelpipe_cache.c:124
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:556
int32_t unmuted
Definition darktable.h:526
Definition pixelpipe_cache.h:40
size_t current_memory
Definition pixelpipe_cache.h:45
GHashTable * entries
Definition pixelpipe_cache.h:41
dt_pthread_mutex_t lock
Definition pixelpipe_cache.h:46
size_t max_memory
Definition pixelpipe_cache.h:44
uint64_t queries
Definition pixelpipe_cache.h:42
uint64_t hits
Definition pixelpipe_cache.h:43
Definition develop/format.h:36
Definition pixelpipe_cache.c:29
uint64_t hash
Definition pixelpipe_cache.c:30
gboolean auto_destroy
Definition pixelpipe_cache.c:39
dt_atomic_int refcount
Definition pixelpipe_cache.c:37
void * data
Definition pixelpipe_cache.c:31
dt_iop_buffer_dsc_t dsc
Definition pixelpipe_cache.c:33
size_t size
Definition pixelpipe_cache.c:32
int64_t age
Definition pixelpipe_cache.c:34
dt_pthread_rwlock_t lock
Definition pixelpipe_cache.c:38
char * name
Definition pixelpipe_cache.c:35
int id
Definition pixelpipe_cache.c:36
#define dt_alloc_align(B)
Definition tests/cache.c:22
#define MIN(a, b)
Definition thinplate.c:23
#define MAX(a, b)
Definition thinplate.c:20