Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
test_pipe_cache_host_stale.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Guillaume Stutin.
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 Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
30#include "system/atomic.h"
31#include "system/dtpthread.h"
32
33#include <stdarg.h>
34#include <stddef.h>
35// cmocka.h declares `extern jmp_buf global_expect_assert_env' at file scope without including
36// <setjmp.h> itself. Same suppression as test_metadata_notify.c, and for the same reason.
37#include <setjmp.h> // NOLINT(misc-include-cleaner)
38#include <stdint.h>
39#include <string.h>
40#include <cmocka.h>
41
42#define LINE_BYTES (256 * 1024)
43#define HASH_A 0x0A0A0A0A0A0A0A0Aull
44#define HASH_B 0x0B0B0B0B0B0B0B0Bull
45#define HASH_C 0x0C0C0C0C0C0C0C0Cull
46
47static int _setup(void **state __attribute__((unused)))
48{
49 return dt_dev_pixelpipe_cache_init((size_t)64 * 1024 * 1024, FALSE, FALSE) ? 0 : -1;
50}
51
52static int _teardown(void **state __attribute__((unused)))
53{
55 return 0;
56}
57
58/* Take a writable line the way the pipeline does, fill its host buffer if asked, and publish it:
59 * write lock and reference released. Returns the entry's metadata snapshot, which is what a piece
60 * keeps as its reuse hint. */
62 const gboolean allow_rekey, const gboolean write_host,
64{
65 void *data = NULL;
69 hint, NULL, &data, &entry);
70 assert_int_equal(status, expected);
71 assert_non_null(entry);
72
73 if(write_host)
74 {
75 void *buffer = dt_pixel_cache_alloc(entry);
76 assert_non_null(buffer);
77 memset(buffer, (int)(hash & 0xff), LINE_BYTES);
79 }
80
81 const dt_pixel_cache_entry_t snapshot = *entry;
84 return snapshot;
85}
86
89{
90 const dt_pixel_cache_entry_t first
92 const dt_pixel_cache_entry_t second
94
95 // Same line, moved: the rekey is what this is about.
96 assert_int_equal(second.serial, first.serial);
98
100 assert_non_null(entry);
101 // The producer still reaches the buffer it backs its output with ...
103 // ... and no reader sees it as the pixels of HASH_B.
105
106 void *data = NULL;
109 assert_null(data);
110
111 // The pipeline's own exact-hit lookup finds the line but no pixels, and must not take it as a hit.
113 assert_null(data);
115
116 // A caller owning no device cannot recover them either.
118}
119
122{
123 const dt_pixel_cache_entry_t first
125 const dt_pixel_cache_entry_t second
127 assert_int_equal(second.serial, first.serial);
128
129 void *data = NULL;
132 assert_non_null(data);
133 assert_int_equal(((const unsigned char *)data)[0], (int)(HASH_C & 0xff));
134 assert_int_equal(((const unsigned char *)data)[LINE_BYTES - 1], (int)(HASH_C & 0xff));
136}
137
140{
141 const dt_pixel_cache_entry_t first
143 const dt_pixel_cache_entry_t second
145 assert_int_not_equal(second.serial, first.serial);
146
147 // Switching back is an exact hit on the untouched line, host pixels included.
148 void *data = NULL;
151 assert_int_equal(((const unsigned char *)data)[0], (int)(HASH_A & 0xff));
153
154 // And the pipeline, asking to write HASH_A again, is told to take it as it is: the line comes back
155 // already referenced, so nothing can evict it before the pipeline reads it.
156 data = NULL;
157 held = NULL;
159 &second, NULL, &data, &held),
161 assert_null(data);
162 assert_non_null(held);
163 assert_int_equal(held->serial, first.serial);
164 // One reference, the caller's own, and no lock: the line is readable, and nothing else holds it.
166 gboolean unlocked = FALSE;
167 if(dt_pthread_rwlock_trywrlock(&held->lock) == 0)
168 {
169 unlocked = TRUE;
171 }
174}
175
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int dt_atomic_get_int(dt_atomic_int *var)
GtkWidget * status
result of the last capture
static int dt_pthread_rwlock_trywrlock(dt_pthread_rwlock_t *rwlock) TRY_ACQUIRE(0
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:217
hash
Definition layers.h:90
void dt_dev_pixelpipe_cache_wrlock_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the write lock on the entry.
void dt_dev_pixelpipe_cache_cleanup(void)
Release everything dt_dev_pixelpipe_cache_init() created, the instance included. Only after a success...
void * dt_pixel_cache_entry_get_data(dt_pixel_cache_entry_t *entry)
Peek the host pixels a cache entry holds for its current hash, without allocating.
void dt_dev_pixelpipe_cache_ref_count_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Take or release one reference on a cache line. A referenced line is never evicted,...
gboolean dt_dev_pixelpipe_cache_peek(const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry, const int preferred_devid, void **cl_mem_output)
Non-owning lookup of an existing cache line.
void * dt_pixel_cache_alloc(dt_pixel_cache_entry_t *cache_entry)
Actually allocate the memory buffer attached to the cache entry once you create it with dt_dev_pixelp...
void * dt_pixel_cache_entry_get_buffer(dt_pixel_cache_entry_t *entry)
The host buffer of a cache entry, whatever hash its content describes.
dt_pixel_cache_entry_t * dt_dev_pixelpipe_cache_get_entry(const uint64_t hash)
Get an internal reference to the cache entry matching hash. If you are going to access this entry mor...
gboolean dt_dev_pixelpipe_cache_init(size_t max_memory, const gboolean verbose, const gboolean verbose_detail)
Reserve the cache's arena and start it.
void dt_dev_pixelpipe_cache_flag_host_written(dt_pixel_cache_entry_t *entry)
Record that the host buffer of entry now holds the pixels of its current hash.
gboolean dt_dev_pixelpipe_cache_ref_entry_by_hash(const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cache entry by hash.
dt_dev_pixelpipe_cache_writable_status_t dt_dev_pixelpipe_cache_get_writable(const uint64_t hash, const size_t size, const char *name, const int id, const gboolean alloc, const gboolean allow_rekey_reuse, const dt_pixel_cache_entry_t *reuse_hint, const dt_pixel_cache_entry_t *reuse_hint_prev, void **data, dt_pixel_cache_entry_t **entry)
gboolean dt_dev_pixelpipe_cache_ref_host_entry_by_hash(const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cacheline that already holds HOST pixels.
Pixelpipe cache for storing intermediate results in the pixelpipe.
dt_dev_pixelpipe_cache_writable_status_t
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_REKEYED
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_CREATED
@ DT_DEV_PIXELPIPE_CACHE_WRITABLE_EXACT_HIT
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
Definition simd.h:55
const float uint32_t state[4]
unsigned __int64 uint64_t
Definition strptime.c:75
dt_atomic_int refcount
void * data
uint64_t serial
dt_pthread_rwlock_t lock
static void _rewritten_line_publishes_its_host_pixels(void **state __attribute__((unused)))
static int _teardown(void **state __attribute__((unused)))
#define HASH_B
static int _setup(void **state __attribute__((unused)))
int main(void)
#define LINE_BYTES
#define HASH_A
static void _without_rekey_the_previous_output_stays(void **state __attribute__((unused)))
static dt_pixel_cache_entry_t _produce(const uint64_t hash, const dt_pixel_cache_entry_t *hint, const gboolean allow_rekey, const gboolean write_host, const dt_dev_pixelpipe_cache_writable_status_t expected)
#define HASH_C
static void _rekeyed_line_publishes_no_host_pixels(void **state __attribute__((unused)))