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 size_t ctx_size; 210 CeedQFunctionContext_Memcheck *impl; 211 212 CeedCallBackend(CeedQFunctionContextGetContextSize(ctx, &ctx_size)); 213 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 214 215 // Verify no changes made during read-only access 216 bool is_changed = memcmp(impl->data_allocated, impl->data_read_only_copy, ctx_size); 217 218 CeedCheck(!is_changed, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, "Context data changed while accessed in read-only mode"); 219 220 // Invalidate read-only buffer 221 memset(impl->data_read_only_copy, -42, ctx_size); 222 CeedCallBackend(CeedFree(&impl->data_read_only_copy)); 223 VALGRIND_DISCARD(impl->read_only_block_id); 224 return CEED_ERROR_SUCCESS; 225 } 226 227 //------------------------------------------------------------------------------ 228 // QFunctionContext destroy user data 229 //------------------------------------------------------------------------------ 230 static int CeedQFunctionContextDataDestroy_Memcheck(CeedQFunctionContext ctx) { 231 CeedMemType data_destroy_mem_type; 232 CeedQFunctionContextDataDestroyUser data_destroy_function; 233 CeedQFunctionContext_Memcheck *impl; 234 235 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 236 237 CeedCallBackend(CeedQFunctionContextGetDataDestroy(ctx, &data_destroy_mem_type, &data_destroy_function)); 238 CeedCheck(data_destroy_mem_type == CEED_MEM_HOST, CeedQFunctionContextReturnCeed(ctx), CEED_ERROR_BACKEND, 239 "Can only destroy HOST memory for this backend"); 240 241 // Run user destroy routine 242 if (data_destroy_function) { 243 bool is_borrowed = !!impl->data_borrowed; 244 245 CeedCallBackend(data_destroy_function(is_borrowed ? impl->data_borrowed : impl->data_owned)); 246 if (is_borrowed) VALGRIND_DISCARD(impl->borrowed_block_id); 247 else VALGRIND_DISCARD(impl->owned_block_id); 248 } 249 // Free allocations and discard block ids 250 if (impl->data_allocated) { 251 CeedCallBackend(CeedFree(&impl->data_allocated)); 252 VALGRIND_DISCARD(impl->allocated_block_id); 253 } 254 if (impl->data_owned) { 255 CeedCallBackend(CeedFree(&impl->data_owned)); 256 VALGRIND_DISCARD(impl->owned_block_id); 257 } 258 if (impl->data_borrowed) { 259 VALGRIND_DISCARD(impl->borrowed_block_id); 260 } 261 return CEED_ERROR_SUCCESS; 262 } 263 264 //------------------------------------------------------------------------------ 265 // QFunctionContext Destroy 266 //------------------------------------------------------------------------------ 267 static int CeedQFunctionContextDestroy_Memcheck(CeedQFunctionContext ctx) { 268 CeedQFunctionContext_Memcheck *impl; 269 270 // Free allocations and discard block ids 271 CeedCallBackend(CeedQFunctionContextGetBackendData(ctx, &impl)); 272 if (impl->data_allocated) { 273 CeedCallBackend(CeedFree(&impl->data_allocated)); 274 VALGRIND_DISCARD(impl->allocated_block_id); 275 } 276 if (impl->data_owned) { 277 CeedCallBackend(CeedFree(&impl->data_owned)); 278 VALGRIND_DISCARD(impl->owned_block_id); 279 } 280 if (impl->data_borrowed) { 281 VALGRIND_DISCARD(impl->borrowed_block_id); 282 } 283 CeedCallBackend(CeedFree(&impl)); 284 return CEED_ERROR_SUCCESS; 285 } 286 287 //------------------------------------------------------------------------------ 288 // QFunctionContext Create 289 //------------------------------------------------------------------------------ 290 int CeedQFunctionContextCreate_Memcheck(CeedQFunctionContext ctx) { 291 Ceed ceed; 292 CeedQFunctionContext_Memcheck *impl; 293 294 CeedCallBackend(CeedQFunctionContextGetCeed(ctx, &ceed)); 295 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "HasValidData", CeedQFunctionContextHasValidData_Memcheck)); 296 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "HasBorrowedDataOfType", CeedQFunctionContextHasBorrowedDataOfType_Memcheck)); 297 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "SetData", CeedQFunctionContextSetData_Memcheck)); 298 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "TakeData", CeedQFunctionContextTakeData_Memcheck)); 299 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "GetData", CeedQFunctionContextGetData_Memcheck)); 300 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "GetDataRead", CeedQFunctionContextGetDataRead_Memcheck)); 301 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "RestoreData", CeedQFunctionContextRestoreData_Memcheck)); 302 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "RestoreDataRead", CeedQFunctionContextRestoreDataRead_Memcheck)); 303 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "DataDestroy", CeedQFunctionContextDataDestroy_Memcheck)); 304 CeedCallBackend(CeedSetBackendFunction(ceed, "QFunctionContext", ctx, "Destroy", CeedQFunctionContextDestroy_Memcheck)); 305 CeedCallBackend(CeedDestroy(&ceed)); 306 CeedCallBackend(CeedCalloc(1, &impl)); 307 CeedCallBackend(CeedQFunctionContextSetBackendData(ctx, impl)); 308 return CEED_ERROR_SUCCESS; 309 } 310 311 //------------------------------------------------------------------------------ 312