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