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 if(cache_entry_found)
316 {
317 // Block and wait for write events to finish, aka try to take a read lock
318 dt_dev_pixelpipe_cache_rdlock_entry(cache, hash, TRUE, cache_entry);
319 dt_dev_pixelpipe_cache_rdlock_entry(cache, hash, FALSE, cache_entry);
320 }
321 else
322 {
323 // Newly-allocated buffer: immediately lock in write mode until the caller
324 // populates the content, so other threads may not lock it in read mode
325 // before there is actually something to read.
326 dt_dev_pixelpipe_cache_wrlock_entry(cache, hash, TRUE, cache_entry);
327 }
328
329 // Set the time after we get the lock
330 cache_entry->age = g_get_monotonic_time(); // this is the MRU entry
331 *data = cache_entry->data;
332 *dsc = &cache_entry->dsc;
333 dt_pixel_cache_message(cache_entry, (cache_entry_found) ? "found" : "created", FALSE);
334
335 // This will become the input for the next module, lock it until next module process ends
337 }
338 else
339 {
340 // Don't write on *dsc and *data here
341 dt_print(DT_DEBUG_PIPE, "couldn't allocate new cache entry %lu\n", hash);
342 }
343
344 if(entry) *entry = cache_entry;
345
347 return !cache_entry_found;
348}
349
351 void **data, dt_iop_buffer_dsc_t **dsc, dt_pixel_cache_entry_t **entry)
352{
353 // Find the cache entry for this hash, if any
355 cache->queries++;
357 if(cache_entry) cache->hits++;
358
359 if(cache_entry)
360 {
361 // Block and wait for write events to finish, aka try to take a read lock
362 dt_dev_pixelpipe_cache_rdlock_entry(cache, hash, TRUE, cache_entry);
363 dt_dev_pixelpipe_cache_rdlock_entry(cache, hash, FALSE, cache_entry);
364
365 // Set the time after we get the lock
366 cache_entry->age = g_get_monotonic_time(); // this is the MRU entry
367 *data = cache_entry->data;
368 *dsc = &cache_entry->dsc;
369 dt_pixel_cache_message(cache_entry, "found", FALSE);
370
371 // This will become the input for the next module, lock it until next module process ends
373 }
374
375 if(entry) *entry = cache_entry;
376
378 return cache_entry != NULL;
379}
380
381
382gboolean _for_each_remove(gpointer key, gpointer value, gpointer user_data)
383{
384 dt_pixel_cache_entry_t *cache_entry = (dt_pixel_cache_entry_t *)value;
385 const int id = GPOINTER_TO_INT(user_data);
386
387 // Returns 1 if the lock is captured by another thread
388 // 0 if WE capture the lock, and then need to release it
389 gboolean locked = dt_pthread_rwlock_trywrlock(&cache_entry->lock);
390 if(!locked) dt_pthread_rwlock_unlock(&cache_entry->lock);
391 gboolean used = dt_atomic_get_int(&cache_entry->refcount) > 0;
392
393 return (cache_entry->id == id || id == -1) && !used && !locked;
394}
395
397{
399 g_hash_table_foreach_remove(cache->entries, _for_each_remove, GINT_TO_POINTER(id));
400 cache->current_memory = 0;
402}
403
409
410
412{
413 GHashTableIter iter;
414 gpointer key, value;
415 uint64_t hash = 0;
416 if(entry) *entry = NULL;
417
418 g_hash_table_iter_init(&iter, cache->entries);
419 while(g_hash_table_iter_next(&iter, &key, &value))
420 {
421 dt_pixel_cache_entry_t *cache_entry = (dt_pixel_cache_entry_t *)value;
422 if(cache_entry->data == data)
423 {
424 hash = cache_entry->hash;
425 if(entry) *entry = cache_entry;
426 break;
427 }
428 }
429
430 return hash;
431}
432
433
441
442
444{
445 dt_pixel_cache_entry_t *cache_entry;
447
448 _non_thread_safe_cache_get_hash_data(cache, data, &cache_entry);
449 if(cache_entry)
450 {
451 dt_pthread_rwlock_rdlock(&cache_entry->lock);
452 dt_pixel_cache_message(cache_entry, "read lock", TRUE);
453 }
454
456 return cache_entry;
457}
458
459
461 dt_pixel_cache_entry_t *cache_entry)
462{
463 if(cache_entry == NULL)
464 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
465
466 if(cache_entry)
467 {
468 if(lock)
469 {
470 dt_atomic_add_int(&cache_entry->refcount, 1);
471 dt_pixel_cache_message(cache_entry, "ref count ++", TRUE);
472 }
473 else
474 {
475 dt_atomic_sub_int(&cache_entry->refcount, 1);
476 dt_pixel_cache_message(cache_entry, "ref count --", TRUE);
477 }
478 }
479}
480
481
483 dt_pixel_cache_entry_t *cache_entry)
484{
486 _non_thread_safe_cache_ref_count_entry(cache, hash, lock, cache_entry);
488}
489
490
492 dt_pixel_cache_entry_t *cache_entry)
493{
494 if(cache_entry == NULL)
495 cache_entry = dt_dev_pixelpipe_cache_get_entry(cache, hash);
496
497 if(cache_entry)
498 {
499 if(lock)
500 {
501 dt_pthread_rwlock_wrlock(&cache_entry->lock);
502 dt_pixel_cache_message(cache_entry, "write lock", TRUE);
503 }
504 else
505 {
506 dt_pthread_rwlock_unlock(&cache_entry->lock);
507 dt_pixel_cache_message(cache_entry, "write unlock", TRUE);
508 }
509 }
510}
511
512
514 dt_pixel_cache_entry_t *cache_entry)
515{
516 if(cache_entry == NULL)
517 cache_entry = dt_dev_pixelpipe_cache_get_entry(cache, hash);
518
519 if(cache_entry)
520 {
521 if(lock)
522 {
523 dt_pthread_rwlock_rdlock(&cache_entry->lock);
524 dt_pixel_cache_message(cache_entry, "read lock", TRUE);
525 }
526 else
527 {
528 dt_pthread_rwlock_unlock(&cache_entry->lock);
529 dt_pixel_cache_message(cache_entry, "read unlock", TRUE);
530 }
531 }
532}
533
534
536 dt_pixel_cache_entry_t *cache_entry)
537{
539 if(cache_entry == NULL)
540 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
541
542 if(cache_entry) cache_entry->auto_destroy = TRUE;
544}
545
546
548 dt_pixel_cache_entry_t *cache_entry)
549{
551 if(cache_entry == NULL)
552 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
553
554 if(cache_entry && cache_entry->auto_destroy && id == cache_entry->id)
555 {
556 cache->current_memory -= cache_entry->size;
557 g_hash_table_remove(cache->entries, GINT_TO_POINTER(hash));
558 }
560}
561
562
564{
565 if(!(darktable.unmuted & DT_DEBUG_PIPE)) return;
566
567 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));
568}
569
570// clang-format off
571// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
572// vim: shiftwidth=2 expandtab tabstop=2 cindent
573// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
574// 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:336
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:319
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:304
#define dt_pthread_rwlock_wrlock
Definition dtpthread.h:339
#define dt_pthread_rwlock_t
Definition dtpthread.h:334
#define dt_pthread_rwlock_trywrlock
Definition dtpthread.h:341
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:324
#define dt_pthread_rwlock_init
Definition dtpthread.h:335
#define dt_pthread_rwlock_unlock
Definition dtpthread.h:337
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:309
#define dt_pthread_rwlock_rdlock
Definition dtpthread.h:338
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:482
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:513
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:491
void dt_dev_pixelpipe_cache_print(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:563
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:396
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:547
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:434
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:535
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:443
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:350
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:460
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:382
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:411
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.
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:405
size_t size
Definition pixelpipe_cache.c:407
void * data
Definition pixelpipe_cache.c:406
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