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
19#include "control/control.h"
21#include "common/darktable.h"
22#include "common/debug.h"
23#include "develop/format.h"
25#include <inttypes.h>
26#include <glib.h>
27#include <stdlib.h>
28
29
31{
32 uint64_t hash; // unique identifier of the entry
33 void *data; // buffer holding pixels... or anything else
34 size_t size; // size of the data buffer
35 dt_iop_buffer_dsc_t dsc; // metadata of the data buffer
36 int64_t age; // timestamp of creation. Oldest entry will be the first freed if it's not locked
37 char *name; // name of the cache entry, for debugging
38 int id; // id of the pipeline owning this entry. Used when flushing, a pipe can only flush its own.
39 dt_atomic_int refcount; // reference count for the cache entry, to avoid freeing it while still in use
40 dt_pthread_rwlock_t lock; // read/write lock to avoid threads conflicts
41 gboolean auto_destroy; // TRUE for auto-destruction the next time it's used. Used for short-lived entries (transient states).
43
44
46 dt_pixel_cache_entry_t *cache_entry);
47
49{
50 return (dt_pixel_cache_entry_t *)g_hash_table_lookup(cache->entries, GINT_TO_POINTER(hash));
51}
52
53
61
62
64{
65 return cache_entry->size / (1024 * 1024);
66}
67
68
69void dt_pixel_cache_message(dt_pixel_cache_entry_t *cache_entry, const char *message, gboolean verbose)
70{
71 if(!(darktable.unmuted & DT_DEBUG_CACHE)) return;
72 if(verbose && !(darktable.unmuted & DT_DEBUG_VERBOSE)) return;
73 dt_print(DT_DEBUG_CACHE, "[pixelpipe] cache entry %" PRIu64 ": %s (%lu MiB - age %" PRId64 ") %s\n", cache_entry->hash,
74 cache_entry->name, dt_pixel_cache_get_size(cache_entry), cache_entry->age, message);
75}
76
77
78// remove the cache entry with the given hash and update the cache memory usage
79// WARNING: not internally thread-safe, protect its calls with mutex lock
80// return 0 on success, 1 on error
81int _non_thread_safe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const gboolean force,
82 dt_pixel_cache_entry_t *cache_entry)
83{
84 if(cache_entry == NULL)
85 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
86
87 if(cache_entry)
88 {
89 // Returns 1 if the lock is captured by another thread
90 // 0 if WE capture the lock, and then need to release it
91 gboolean locked = dt_pthread_rwlock_trywrlock(&cache_entry->lock);
92 if(!locked) dt_pthread_rwlock_unlock(&cache_entry->lock);
93 gboolean used = dt_atomic_get_int(&cache_entry->refcount) > 0;
94
95 if((!used || force) && !locked)
96 {
97 cache->current_memory -= cache_entry->size;
98 g_hash_table_remove(cache->entries, GINT_TO_POINTER(hash));
99 return 0;
100 }
101 else if(used)
102 dt_pixel_cache_message(cache_entry, "cannot remove: used", TRUE);
103 else if(locked)
104 dt_pixel_cache_message(cache_entry, "cannot remove: locked", TRUE);
105 }
106 else
107 {
108 dt_print(DT_DEBUG_PIPE, "[pixelpipe] cache entry %" PRIu64 " not found, will not be removed\n", hash);
109 }
110 return 1;
111}
112
113
114int dt_dev_pixelpipe_cache_remove(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, const gboolean force,
115 dt_pixel_cache_entry_t *cache_entry)
116{
118 int error = _non_thread_safe_cache_remove(cache, hash, force, cache_entry);
120 return error;
121}
122
129
130
131// find the cache entry hash with the oldest use
132void _cache_get_oldest(gpointer key, gpointer value, gpointer user_data)
133{
134 dt_pixel_cache_entry_t *cache_entry = (dt_pixel_cache_entry_t *)value;
135 _cache_lru_t *lru = (_cache_lru_t *)user_data;
136
137 // Don't remove LRU entries that are still in use
138 // NOTE: with all the killswitches mechanisms and safety measures,
139 // we might have more things decreasing refcount than increasing it.
140 // It's no big deal though, as long as the (final output) backbuf
141 // is checked for NULL and not reused if pipeline is DIRTY.
142 if(cache_entry->age < lru->max_age)
143 {
144 // Returns 1 if the lock is captured by another thread
145 // 0 if WE capture the lock, and then need to release it
146 gboolean locked = dt_pthread_rwlock_trywrlock(&cache_entry->lock);
147 if(!locked) dt_pthread_rwlock_unlock(&cache_entry->lock);
148 gboolean used = dt_atomic_get_int(&cache_entry->refcount) > 0;
149
150 if(!locked && !used)
151 {
152 lru->max_age = cache_entry->age;
153 lru->hash = cache_entry->hash;
154 lru->cache_entry = cache_entry;
155 dt_pixel_cache_message(cache_entry, "candidate for deletion", TRUE);
156 }
157 else if(used)
158 dt_pixel_cache_message(cache_entry, "cannot be deleted: used", TRUE);
159 else if(locked)
160 dt_pixel_cache_message(cache_entry, "cannot be deleted: locked", TRUE);
161 }
162}
163
164
165// remove the least used cache entry
166// return 0 on success, 1 on error
167// error is : we couldn't find a candidate for deletion because all entries are either locked or in use
168// or we found one but failed to remove it.
170{
171 _cache_lru_t *lru = (_cache_lru_t *)malloc(sizeof(_cache_lru_t));
172 lru->max_age = g_get_monotonic_time();
173 lru->hash = 0;
174 lru->cache_entry = NULL;
175 int error = 1;
176 g_hash_table_foreach(cache->entries, _cache_get_oldest, lru);
177
178 if(lru->hash > 0)
180 else
181 dt_print(DT_DEBUG_PIPE, "[pixelpipe] couldn't remove LRU, %i items and all are used\n", g_hash_table_size(cache->entries));
182
183 free(lru);
184 return error;
185}
186
187// return 0 on success 1 on error
195
196// WARNING: not thread-safe, protect its calls with mutex lock
198 const dt_iop_buffer_dsc_t dsc, const char *name, const int id,
200{
201 // Dynamically update the max cache size depending on remaining free memory on system
202 const size_t remaining_mem = dt_get_available_mem();
203 const size_t safety_margin = 4 * dt_get_singlebuffer_mem();
204 if(remaining_mem < safety_margin)
205 {
206 cache->max_memory
207 = MIN(MAX((int64_t)remaining_mem - (int64_t)safety_margin, (int64_t)2 * dt_get_singlebuffer_mem()),
208 remaining_mem);
209 //fprintf(stdout, "new pipeline cache size : %lu MiB\n", cache->max_memory / (1024 * 1024));
210 if(cache->max_memory == 2 * dt_get_singlebuffer_mem())
211 dt_control_log(_("Your system RAM is nearly saturated.\n"
212 "Processing full-resolution images may not "
213 "possible anymore.\n"));
214 }
215
216 // Free up space if needed to match the max memory limit
217 // If error, all entries are currently locked or in use, so we cannot free space to allocate a new entry.
218 int error = 0;
219 while(cache->current_memory + size > cache->max_memory && g_hash_table_size(cache->entries) > 0 && !error)
221
222 if(cache->current_memory + size > cache->max_memory)
223 {
224 dt_print(DT_DEBUG_PIPE, "[pixelpipe] cache is full, cannot allocate new entry %" PRIu64 " (%s)\n", hash, name);
225 return NULL; // not enough memory
226 }
227
229 if(!cache_entry) return NULL;
230
231 // allocate the data buffer
232 cache_entry->data = dt_alloc_align(size);
233
234 // if allocation failed, remove the least recently used cache entry, then try again
235 while(cache_entry->data == NULL && g_hash_table_size(cache->entries) > 0)
236 {
238 cache_entry->data = dt_alloc_align(size);
239 }
240
241 if(!cache_entry->data)
242 {
243 free(cache_entry);
244 return NULL;
245 }
246
247 cache_entry->size = size;
248 cache_entry->age = 0;
249 cache_entry->dsc = dsc;
250 cache_entry->hash = hash;
251 cache_entry->id = id;
252 cache_entry->name = g_strdup(name);
253 cache_entry->refcount = 0;
254 cache_entry->auto_destroy = FALSE;
255 dt_pthread_rwlock_init(&cache_entry->lock, NULL);
256
257 g_hash_table_insert(cache->entries, GINT_TO_POINTER(hash), cache_entry);
258 cache->current_memory += size;
259
260 return cache_entry;
261}
262
263
265{
266 if(!cache_entry) return;
267 dt_pixel_cache_message(cache_entry, "freed", FALSE);
268 dt_free_align(cache_entry->data);
269 cache_entry->data = NULL;
270 dt_pthread_rwlock_destroy(&cache_entry->lock);
271 g_free(cache_entry->name);
272 free(cache_entry);
273}
274
275
277{
279 dt_pthread_mutex_init(&cache->lock, NULL);
280 cache->entries = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)_free_cache_entry);
281 cache->max_memory = max_memory;
282 cache->current_memory = 0;
283 cache->queries = cache->hits = 0;
284 return cache;
285}
286
287
289{
290 if(!cache) return;
292 g_hash_table_destroy(cache->entries);
293 cache->entries = NULL;
294}
295
296
298 const size_t size, const char *name, const int id,
299 void **data, dt_iop_buffer_dsc_t **dsc,
301{
302 // Search or create cache entry (under cache lock)
304 cache->queries++;
305
307 const gboolean cache_entry_found = (cache_entry != NULL);
308
309 if(cache_entry_found)
310 {
311 // Existing entry: increment hit counter
312 cache->hits++;
313
314 // Increase ref_count, consumer will have to decrease it
316
317 // Release cache lock BEFORE acquiring entry locks to avoid deadlock
319 }
320 else
321 {
322 // New entry: create and allocate
323 cache_entry = dt_pixel_cache_new_entry(hash, size, **dsc, name, id, cache);
324
325 if(!cache_entry)
326 {
327 dt_print(DT_DEBUG_PIPE, "couldn't allocate new cache entry %" PRIu64 "\n", hash);
329 if(entry) *entry = NULL;
330 return 1;
331 }
332
333 // Increase ref_count, consumer will have to decrease it
335
336 // Acquire write lock so caller can populate data safely
337 dt_dev_pixelpipe_cache_wrlock_entry(cache, hash, TRUE, cache_entry);
338
339 // Release cache lock AFTER acquiring entry locks to prevent other threads to capture it in-between
341
342 dt_print(DT_DEBUG_CACHE,"[pixelpipe_cache] Write-lock on entry (new cache entry %" PRIu64 " for %s pipeline)\n", hash, name);
343 }
344
345 // Finalize and return
346 cache_entry->age = g_get_monotonic_time(); // Update MRU timestamp
347 *data = cache_entry->data;
348 *dsc = &cache_entry->dsc;
349 dt_pixel_cache_message(cache_entry, cache_entry_found ? "found" : "created", FALSE);
350
351 if(entry) *entry = cache_entry;
352 return !cache_entry_found;
353}
354
356 void **data, dt_iop_buffer_dsc_t **dsc, dt_pixel_cache_entry_t **entry)
357{
358 // Find the cache entry for this hash, if any
360 cache->queries++;
362
363 if(cache_entry)
364 {
365 cache->hits++;
366 // Increment refcount while we still hold cache->lock
368
369 // Set the time after we get the lock
370 cache_entry->age = g_get_monotonic_time(); // this is the MRU entry
371 *data = cache_entry->data;
372 *dsc = &cache_entry->dsc;
373 dt_pixel_cache_message(cache_entry, "found", FALSE);
374 }
375
377
378 if(entry) *entry = cache_entry;
379 return cache_entry != NULL;
380}
381
382
383gboolean _for_each_remove(gpointer key, gpointer value, gpointer user_data)
384{
385 dt_pixel_cache_entry_t *cache_entry = (dt_pixel_cache_entry_t *)value;
386 const int id = GPOINTER_TO_INT(user_data);
387
388 // Returns 1 if the lock is captured by another thread
389 // 0 if WE capture the lock, and then need to release it
390 gboolean locked = dt_pthread_rwlock_trywrlock(&cache_entry->lock);
391 if(!locked) dt_pthread_rwlock_unlock(&cache_entry->lock);
392 gboolean used = dt_atomic_get_int(&cache_entry->refcount) > 0;
393
394 return (cache_entry->id == id || id == -1) && !used && !locked;
395}
396
398{
400 g_hash_table_foreach_remove(cache->entries, _for_each_remove, GINT_TO_POINTER(id));
401 cache->current_memory = 0;
403}
404
410
411
413{
414 GHashTableIter iter;
415 gpointer key, value;
416 uint64_t hash = 0;
417 if(entry) *entry = NULL;
418
419 g_hash_table_iter_init(&iter, cache->entries);
420 while(g_hash_table_iter_next(&iter, &key, &value))
421 {
422 dt_pixel_cache_entry_t *cache_entry = (dt_pixel_cache_entry_t *)value;
423 if(cache_entry->data == data)
424 {
425 hash = cache_entry->hash;
426 if(entry) *entry = cache_entry;
427 break;
428 }
429 }
430
431 return hash;
432}
433
434
442
443
445{
446 dt_pixel_cache_entry_t *cache_entry;
448
449 _non_thread_safe_cache_get_hash_data(cache, data, &cache_entry);
450 if(cache_entry)
451 {
452 dt_pthread_rwlock_rdlock(&cache_entry->lock);
453 dt_pixel_cache_message(cache_entry, "read lock", TRUE);
454 }
455
457 return cache_entry;
458}
459
460
462 dt_pixel_cache_entry_t *cache_entry)
463{
464 if(cache_entry == NULL)
465 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
466
467 if(cache_entry)
468 {
469 if(lock)
470 {
471 dt_atomic_add_int(&cache_entry->refcount, 1);
472 dt_pixel_cache_message(cache_entry, "ref count ++", TRUE);
473 }
474 else
475 {
476 dt_atomic_sub_int(&cache_entry->refcount, 1);
477 dt_pixel_cache_message(cache_entry, "ref count --", TRUE);
478 }
479 }
480}
481
482
484 dt_pixel_cache_entry_t *cache_entry)
485{
487 _non_thread_safe_cache_ref_count_entry(cache, hash, lock, cache_entry);
489}
490
491
493 dt_pixel_cache_entry_t *cache_entry)
494{
495 if(cache_entry == NULL)
496 cache_entry = dt_dev_pixelpipe_cache_get_entry(cache, hash);
497
498 if(cache_entry)
499 {
500 if(lock)
501 {
502 dt_pthread_rwlock_wrlock(&cache_entry->lock);
503 dt_pixel_cache_message(cache_entry, "write lock", TRUE);
504 }
505 else
506 {
507 dt_pthread_rwlock_unlock(&cache_entry->lock);
508 dt_pixel_cache_message(cache_entry, "write unlock", TRUE);
509 }
510 }
511}
512
513
515 dt_pixel_cache_entry_t *cache_entry)
516{
517 if(cache_entry == NULL)
518 cache_entry = dt_dev_pixelpipe_cache_get_entry(cache, hash);
519
520 if(cache_entry)
521 {
522 if(lock)
523 {
524 dt_pthread_rwlock_rdlock(&cache_entry->lock);
525 dt_pixel_cache_message(cache_entry, "read lock", TRUE);
526 }
527 else
528 {
529 dt_pthread_rwlock_unlock(&cache_entry->lock);
530 dt_pixel_cache_message(cache_entry, "read unlock", TRUE);
531 }
532 }
533}
534
535
537 dt_pixel_cache_entry_t *cache_entry)
538{
540 if(cache_entry == NULL)
541 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
542
543 if(cache_entry) cache_entry->auto_destroy = TRUE;
545}
546
547
549 dt_pixel_cache_entry_t *cache_entry)
550{
552 if(cache_entry == NULL)
553 cache_entry = _non_threadsafe_cache_get_entry(cache, hash);
554
555 if(cache_entry && cache_entry->auto_destroy && id == cache_entry->id)
556 {
557 cache->current_memory -= cache_entry->size;
558 g_hash_table_remove(cache->entries, GINT_TO_POINTER(hash));
559 }
561}
562
563
565{
566 if(!(darktable.unmuted & DT_DEBUG_PIPE)) return;
567
568 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));
569}
570
571// clang-format off
572// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
573// vim: shiftwidth=2 expandtab tabstop=2 cindent
574// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
575// 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:456
darktable_t darktable
Definition darktable.c:111
size_t dt_get_singlebuffer_mem()
Definition darktable.c:1570
size_t dt_get_available_mem()
Definition darktable.c:1557
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1417
@ DT_DEBUG_PIPE
Definition darktable.h:497
@ DT_DEBUG_VERBOSE
Definition darktable.h:499
@ DT_DEBUG_CACHE
Definition darktable.h:472
#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:114
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:483
size_t dt_pixel_cache_get_size(dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_cache.c:63
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:514
void dt_dev_pixelpipe_cache_cleanup(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:288
void _cache_get_oldest(gpointer key, gpointer value, gpointer user_data)
Definition pixelpipe_cache.c:132
dt_dev_pixelpipe_cache_t * dt_dev_pixelpipe_cache_init(size_t max_memory)
Definition pixelpipe_cache.c:276
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:492
void dt_dev_pixelpipe_cache_print(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:564
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:397
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:548
static int _non_thread_safe_pixel_pipe_cache_remove_lru(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:169
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:435
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:197
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:536
int dt_dev_pixel_pipe_cache_remove_lru(dt_dev_pixelpipe_cache_t *cache)
Definition pixelpipe_cache.c:188
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:444
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:355
static void _free_cache_entry(dt_pixel_cache_entry_t *cache_entry)
Definition pixelpipe_cache.c:264
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:54
dt_pixel_cache_entry_t * _non_threadsafe_cache_get_entry(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash)
Definition pixelpipe_cache.c:48
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:461
void dt_pixel_cache_message(dt_pixel_cache_entry_t *cache_entry, const char *message, gboolean verbose)
Definition pixelpipe_cache.c:69
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:81
gboolean _for_each_remove(gpointer key, gpointer value, gpointer user_data)
Definition pixelpipe_cache.c:383
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:412
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:297
Pixelpipe cache for storing intermediate results in the pixelpipe.
unsigned __int64 uint64_t
Definition strptime.c:71
Definition pixelpipe_cache.c:406
size_t size
Definition pixelpipe_cache.c:408
void * data
Definition pixelpipe_cache.c:407
Definition pixelpipe_cache.c:124
int64_t max_age
Definition pixelpipe_cache.c:125
dt_pixel_cache_entry_t * cache_entry
Definition pixelpipe_cache.c:127
uint64_t hash
Definition pixelpipe_cache.c:126
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:31
uint64_t hash
Definition pixelpipe_cache.c:32
gboolean auto_destroy
Definition pixelpipe_cache.c:41
dt_atomic_int refcount
Definition pixelpipe_cache.c:39
void * data
Definition pixelpipe_cache.c:33
dt_iop_buffer_dsc_t dsc
Definition pixelpipe_cache.c:35
size_t size
Definition pixelpipe_cache.c:34
int64_t age
Definition pixelpipe_cache.c:36
dt_pthread_rwlock_t lock
Definition pixelpipe_cache.c:40
char * name
Definition pixelpipe_cache.c:37
int id
Definition pixelpipe_cache.c:38
#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