xref: /libCEED/rust/libceed-sys/c-src/backends/memcheck/ceed-memcheck-qfunctioncontext.c (revision 0307dd026e7027ceb655d92ffb4302ee80e86e93)
1 // Copyright (c) 2017-2024, Lawrence Livermore National Security, LLC and other CEED contributors.
2 // All Rights Reserved. See the top-level LICENSE and NOTICE files for details.
3 //
4 // SPDX-License-Identifier: BSD-2-Clause
5 //
6 // This file is part of CEED:  http://github.com/ceed
7 
8 #include <ceed.h>
9 #include <ceed/backend.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <valgrind/memcheck.h>
13 
14 #include "ceed-memcheck.h"
15 
16 //------------------------------------------------------------------------------
17 // QFunctionContext has valid data
18 //------------------------------------------------------------------------------
19 static int CeedQFunctionContextHasValidData_Memcheck(CeedQFunctionContext ctx, bool *has_valid_data) {
20   CeedQFunctionContext_Memcheck *impl;
21 
22   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
23   *has_valid_data = !!impl->data_allocated;
24   return CEED_ERROR_SUCCESS;
25 }
26 
27 //------------------------------------------------------------------------------
28 // QFunctionContext has borrowed data
29 //------------------------------------------------------------------------------
30 static int CeedQFunctionContextHasBorrowedDataOfType_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, bool *has_borrowed_data_of_type) {
31   CeedQFunctionContext_Memcheck *impl;
32 
33   CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend");
34 
35   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
36   *has_borrowed_data_of_type = !!impl->data_borrowed;
37   return CEED_ERROR_SUCCESS;
38 }
39 
40 //------------------------------------------------------------------------------
41 // QFunctionContext Set Data
42 //------------------------------------------------------------------------------
43 static int CeedQFunctionContextSetData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, CeedCopyMode copy_mode, void *data) {
44   size_t                         ctx_size;
45   CeedQFunctionContext_Memcheck *impl;
46 
47   CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend");
48 
49   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
50   CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size));
51 
52   // Clear previous owned data buffers
53   if (impl->data_allocated) {
54     memset(impl->data_allocated, -42, ctx_size);
55     VALGRIND_DISCARD(impl->allocated_block_id);
56   }
57   CeedCallBackend(CeedFree(&impl->data_allocated));
58   if (impl->data_owned) {
59     memset(impl->data_owned, -42, ctx_size);
60     VALGRIND_DISCARD(impl->owned_block_id);
61   }
62   CeedCallBackend(CeedFree(&impl->data_owned));
63 
64   // Clear borrowed block id, if present
65   if (impl->data_borrowed) VALGRIND_DISCARD(impl->borrowed_block_id);
66 
67   // Set internal pointers to external buffers
68   switch (copy_mode) {
69     case CEED_COPY_VALUES:
70       impl->data_owned    = NULL;
71       impl->data_borrowed = NULL;
72       break;
73     case CEED_OWN_POINTER:
74       impl->data_owned     = data;
75       impl->data_borrowed  = NULL;
76       impl->owned_block_id = VALGRIND_CREATE_BLOCK(impl->data_owned, ctx_size, "Owned external data buffer");
77       break;
78     case CEED_USE_POINTER:
79       impl->data_owned     = NULL;
80       impl->data_borrowed  = data;
81       impl->owned_block_id = VALGRIND_CREATE_BLOCK(impl->data_borrowed, ctx_size, "Borrowed external data buffer");
82   }
83 
84   // Create internal data buffer
85   CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_allocated));
86   impl->allocated_block_id = VALGRIND_CREATE_BLOCK(impl->data_allocated, ctx_size, "'Allocated internal context data buffer");
87   memcpy(impl->data_allocated, data, ctx_size);
88   return CEED_ERROR_SUCCESS;
89 }
90 
91 //------------------------------------------------------------------------------
92 // Sync data
93 //------------------------------------------------------------------------------
94 static int CeedQFunctionContextSyncData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type) {
95   size_t                         ctx_size;
96   CeedQFunctionContext_Memcheck *impl;
97 
98   CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend");
99 
100   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
101   CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size));
102 
103   // Copy internal buffer back to owned or borrowed data buffer
104   if (impl->data_owned) {
105     memcpy(impl->data_owned, impl->data_allocated, ctx_size);
106   }
107   if (impl->data_borrowed) {
108     memcpy(impl->data_borrowed, impl->data_allocated, ctx_size);
109   }
110   return CEED_ERROR_SUCCESS;
111 }
112 
113 //------------------------------------------------------------------------------
114 // QFunctionContext Take Data
115 //------------------------------------------------------------------------------
116 static int CeedQFunctionContextTakeData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) {
117   size_t                         ctx_size;
118   CeedQFunctionContext_Memcheck *impl;
119 
120   CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend");
121 
122   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
123   CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size));
124 
125   // Synchronize memory
126   CeedCallBackend(CeedQFunctionContextSyncData_Memcheck(ctx, CEED_MEM_HOST));
127 
128   // Return borrowed buffer
129   *(void **)data      = impl->data_borrowed;
130   impl->data_borrowed = NULL;
131   VALGRIND_DISCARD(impl->borrowed_block_id);
132 
133   // De-allocate internal memory
134   if (impl->data_allocated) {
135     memset(impl->data_allocated, -42, ctx_size);
136     VALGRIND_DISCARD(impl->allocated_block_id);
137   }
138   CeedCallBackend(CeedFree(&impl->data_allocated));
139   return CEED_ERROR_SUCCESS;
140 }
141 
142 //------------------------------------------------------------------------------
143 // QFunctionContext Get Data
144 //------------------------------------------------------------------------------
145 static int CeedQFunctionContextGetData_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) {
146   size_t                         ctx_size;
147   CeedQFunctionContext_Memcheck *impl;
148 
149   CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend");
150 
151   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
152   CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size));
153 
154   // Create and return writable buffer
155   CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_writable_copy));
156   impl->writable_block_id = VALGRIND_CREATE_BLOCK(impl->data_writable_copy, ctx_size, "Allocated writeable data buffer copy");
157   memcpy(impl->data_writable_copy, impl->data_allocated, ctx_size);
158   *(void **)data = impl->data_writable_copy;
159   return CEED_ERROR_SUCCESS;
160 }
161 
162 //------------------------------------------------------------------------------
163 // QFunctionContext Get Data Read-Only
164 //------------------------------------------------------------------------------
165 static int CeedQFunctionContextGetDataRead_Memcheck(CeedQFunctionContext ctx, CeedMemType mem_type, void *data) {
166   size_t                         ctx_size;
167   CeedQFunctionContext_Memcheck *impl;
168 
169   CeedCheck(mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend");
170 
171   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
172   CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size));
173 
174   // Create and return read-only buffer
175   if (!impl->data_read_only_copy) {
176     CeedCallBackend(CeedMallocArray(1, ctx_size, &impl->data_read_only_copy));
177     impl->writable_block_id = VALGRIND_CREATE_BLOCK(impl->data_read_only_copy, ctx_size, "Allocated read-only data buffer copy");
178     memcpy(impl->data_read_only_copy, impl->data_allocated, ctx_size);
179   }
180   *(void **)data = impl->data_read_only_copy;
181   return CEED_ERROR_SUCCESS;
182 }
183 
184 //------------------------------------------------------------------------------
185 // QFunctionContext Restore Data
186 //------------------------------------------------------------------------------
187 static int CeedQFunctionContextRestoreData_Memcheck(CeedQFunctionContext ctx) {
188   size_t                         ctx_size;
189   CeedQFunctionContext_Memcheck *impl;
190 
191   CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size));
192   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
193 
194   // Copy back to internal buffer and sync
195   memcpy(impl->data_allocated, impl->data_writable_copy, ctx_size);
196   CeedCallBackend(CeedQFunctionContextSyncData_Memcheck(ctx, CEED_MEM_HOST));
197 
198   // Invalidate writable buffer
199   memset(impl->data_writable_copy, -42, ctx_size);
200   CeedCallBackend(CeedFree(&impl->data_writable_copy));
201   VALGRIND_DISCARD(impl->writable_block_id);
202   return CEED_ERROR_SUCCESS;
203 }
204 
205 //------------------------------------------------------------------------------
206 // QFunctionContext Restore Data Read-Only
207 //------------------------------------------------------------------------------
208 static int CeedQFunctionContextRestoreDataRead_Memcheck(CeedQFunctionContext ctx) {
209   Ceed                           ceed;
210   size_t                         ctx_size;
211   CeedQFunctionContext_Memcheck *impl;
212 
213   CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed));
214   CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size));
215   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
216 
217   // Verify no changes made during read-only access
218   bool is_changed = memcmp(impl->data_allocated, impl->data_read_only_copy, ctx_size);
219 
220   CeedCheck(!is_changed, ceed, CEED_ERROR_BACKEND, "Context data changed while accessed in read-only mode");
221 
222   // Invalidate read-only buffer
223   memset(impl->data_read_only_copy, -42, ctx_size);
224   CeedCallBackend(CeedFree(&impl->data_read_only_copy));
225   VALGRIND_DISCARD(impl->read_only_block_id);
226   return CEED_ERROR_SUCCESS;
227 }
228 
229 //------------------------------------------------------------------------------
230 // QFunctionContext destroy user data
231 //------------------------------------------------------------------------------
232 static int CeedQFunctionContextDataDestroy_Memcheck(CeedQFunctionContext ctx) {
233   Ceed                                ceed;
234   CeedMemType                         data_destroy_mem_type;
235   CeedQFunctionContextDataDestroyUser data_destroy_function;
236   CeedQFunctionContext_Memcheck      *impl;
237 
238   CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed));
239   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
240 
241   CeedCallBackend(CeedQFunctionContextGetDataDestroy(ctx, &data_destroy_mem_type, &data_destroy_function));
242   CeedCheck(data_destroy_mem_type == CEED_MEM_HOST, ceed, CEED_ERROR_BACKEND, "Can only destroy HOST memory for this backend");
243 
244   // Run user destroy routine
245   if (data_destroy_function) {
246     bool is_borrowed = !!impl->data_borrowed;
247 
248     CeedCallBackend(data_destroy_function(is_borrowed ? impl->data_borrowed : impl->data_owned));
249     if (is_borrowed) VALGRIND_DISCARD(impl->borrowed_block_id);
250     else VALGRIND_DISCARD(impl->owned_block_id);
251   }
252   // Free allocations and discard block ids
253   if (impl->data_allocated) {
254     CeedCallBackend(CeedFree(&impl->data_allocated));
255     VALGRIND_DISCARD(impl->allocated_block_id);
256   }
257   if (impl->data_owned) {
258     CeedCallBackend(CeedFree(&impl->data_owned));
259     VALGRIND_DISCARD(impl->owned_block_id);
260   }
261   if (impl->data_borrowed) {
262     VALGRIND_DISCARD(impl->borrowed_block_id);
263   }
264   return CEED_ERROR_SUCCESS;
265 }
266 
267 //------------------------------------------------------------------------------
268 // QFunctionContext Destroy
269 //------------------------------------------------------------------------------
270 static int CeedQFunctionContextDestroy_Memcheck(CeedQFunctionContext ctx) {
271   CeedQFunctionContext_Memcheck *impl;
272 
273   // Free allocations and discard block ids
274   CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl));
275   if (impl->data_allocated) {
276     CeedCallBackend(CeedFree(&impl->data_allocated));
277     VALGRIND_DISCARD(impl->allocated_block_id);
278   }
279   if (impl->data_owned) {
280     CeedCallBackend(CeedFree(&impl->data_owned));
281     VALGRIND_DISCARD(impl->owned_block_id);
282   }
283   if (impl->data_borrowed) {
284     VALGRIND_DISCARD(impl->borrowed_block_id);
285   }
286   CeedCallBackend(CeedFree(&impl));
287   return CEED_ERROR_SUCCESS;
288 }
289 
290 //------------------------------------------------------------------------------
291 // QFunctionContext Create
292 //------------------------------------------------------------------------------
293 int CeedQFunctionContextCreate_Memcheck(CeedQFunctionContext ctx) {
294   Ceed                           ceed;
295   CeedQFunctionContext_Memcheck *impl;
296 
297   CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed));
298   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "HasValidData", CeedQFunctionContextHasValidData_Memcheck));
299   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "HasBorrowedDataOfType", CeedQFunctionContextHasBorrowedDataOfType_Memcheck));
300   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "SetData", CeedQFunctionContextSetData_Memcheck));
301   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "TakeData", CeedQFunctionContextTakeData_Memcheck));
302   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "GetData", CeedQFunctionContextGetData_Memcheck));
303   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "GetDataRead", CeedQFunctionContextGetDataRead_Memcheck));
304   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "RestoreData", CeedQFunctionContextRestoreData_Memcheck));
305   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "RestoreDataRead", CeedQFunctionContextRestoreDataRead_Memcheck));
306   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "DataDestroy", CeedQFunctionContextDataDestroy_Memcheck));
307   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "Destroy", CeedQFunctionContextDestroy_Memcheck));
308   CeedCallBackend(CeedCalloc(1, &impl));
309   CeedCallBackend(CeedQFunctionContextSetBackendData(ctx, impl));
310   return CEED_ERROR_SUCCESS;
311 }
312 
313 //------------------------------------------------------------------------------
314