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 <math.h> 11 #include <stdbool.h> 12 #include <string.h> 13 #include <valgrind/memcheck.h> 14 15 #include "ceed-memcheck.h" 16 17 //------------------------------------------------------------------------------ 18 // Has Valid Array 19 //------------------------------------------------------------------------------ 20 static int CeedVectorHasValidArray_Memcheck(CeedVector vec, bool *has_valid_array) { 21 CeedVector_Memcheck *impl; 22 23 CeedCallBackend(CeedVectorGetData(vec, &impl)); 24 *has_valid_array = impl->array; 25 return CEED_ERROR_SUCCESS; 26 } 27 28 //------------------------------------------------------------------------------ 29 // Check if has borrowed array of given type 30 //------------------------------------------------------------------------------ 31 static inline int CeedVectorHasBorrowedArrayOfType_Memcheck(const CeedVector vec, CeedMemType mem_type, bool *has_borrowed_array_of_type) { 32 CeedVector_Memcheck *impl; 33 34 CeedCallBackend(CeedVectorGetData(vec, &impl)); 35 CeedCheck(mem_type == CEED_MEM_HOST, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend"); 36 *has_borrowed_array_of_type = impl->array_borrowed; 37 return CEED_ERROR_SUCCESS; 38 } 39 40 //------------------------------------------------------------------------------ 41 // Vector Set Array 42 //------------------------------------------------------------------------------ 43 static int CeedVectorSetArray_Memcheck(CeedVector vec, CeedMemType mem_type, CeedCopyMode copy_mode, CeedScalar *array) { 44 CeedSize length; 45 CeedVector_Memcheck *impl; 46 47 CeedCallBackend(CeedVectorGetData(vec, &impl)); 48 CeedCallBackend(CeedVectorGetLength(vec, &length)); 49 50 CeedCheck(mem_type == CEED_MEM_HOST, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "Can only set HOST memory for this backend"); 51 52 if (impl->array_allocated) { 53 for (CeedSize i = 0; i < length; i++) impl->array_allocated[i] = NAN; 54 } 55 CeedCallBackend(CeedFree(&impl->array_allocated)); 56 if (impl->array_owned) { 57 for (CeedSize i = 0; i < length; i++) impl->array_owned[i] = NAN; 58 } 59 CeedCallBackend(CeedFree(&impl->array_owned)); 60 switch (copy_mode) { 61 case CEED_COPY_VALUES: 62 CeedCallBackend(CeedCalloc(length, &impl->array_owned)); 63 impl->array_borrowed = NULL; 64 impl->array = impl->array_owned; 65 if (array) { 66 memcpy(impl->array, array, length * sizeof(CeedScalar)); 67 } else { 68 for (CeedInt i = 0; i < length; i++) impl->array[i] = NAN; 69 } 70 break; 71 case CEED_OWN_POINTER: 72 impl->array_owned = array; 73 impl->array_borrowed = NULL; 74 impl->array = array; 75 break; 76 case CEED_USE_POINTER: 77 impl->array_borrowed = array; 78 impl->array = array; 79 } 80 // Copy data to check access 81 CeedCallBackend(CeedCalloc(length, &impl->array_allocated)); 82 memcpy(impl->array_allocated, impl->array, length * sizeof(CeedScalar)); 83 impl->array = impl->array_allocated; 84 VALGRIND_DISCARD(impl->mem_block_id); 85 impl->mem_block_id = VALGRIND_CREATE_BLOCK(impl->array, length * sizeof(CeedScalar), "'Vector backend array data copy'"); 86 return CEED_ERROR_SUCCESS; 87 } 88 89 //------------------------------------------------------------------------------ 90 // Vector Take Array 91 //------------------------------------------------------------------------------ 92 static int CeedVectorTakeArray_Memcheck(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 93 CeedSize length; 94 CeedVector_Memcheck *impl; 95 96 CeedCallBackend(CeedVectorGetData(vec, &impl)); 97 CeedCallBackend(CeedVectorGetLength(vec, &length)); 98 99 CeedCheck(mem_type == CEED_MEM_HOST, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 100 101 (*array) = impl->array_borrowed; 102 impl->array_borrowed = NULL; 103 impl->array = NULL; 104 VALGRIND_DISCARD(impl->mem_block_id); 105 if (impl->array_allocated) { 106 for (CeedSize i = 0; i < length; i++) impl->array_allocated[i] = NAN; 107 } 108 CeedCallBackend(CeedFree(&impl->array_allocated)); 109 return CEED_ERROR_SUCCESS; 110 } 111 112 //------------------------------------------------------------------------------ 113 // Vector Get Array 114 //------------------------------------------------------------------------------ 115 static int CeedVectorGetArray_Memcheck(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 116 CeedSize length; 117 CeedVector_Memcheck *impl; 118 119 CeedCallBackend(CeedVectorGetData(vec, &impl)); 120 CeedCallBackend(CeedVectorGetLength(vec, &length)); 121 122 CeedCheck(mem_type == CEED_MEM_HOST, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 123 124 CeedCallBackend(CeedCalloc(length, &impl->array_writable_copy)); 125 memcpy(impl->array_writable_copy, impl->array, length * sizeof(CeedScalar)); 126 *array = impl->array_writable_copy; 127 return CEED_ERROR_SUCCESS; 128 } 129 130 //------------------------------------------------------------------------------ 131 // Vector Get Array Read 132 //------------------------------------------------------------------------------ 133 static int CeedVectorGetArrayRead_Memcheck(CeedVector vec, CeedMemType mem_type, const CeedScalar **array) { 134 CeedSize length; 135 CeedVector_Memcheck *impl; 136 137 CeedCallBackend(CeedVectorGetData(vec, &impl)); 138 CeedCallBackend(CeedVectorGetLength(vec, &length)); 139 140 CeedCheck(mem_type == CEED_MEM_HOST, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 141 142 // Make copy to verify no write occurred 143 if (!impl->array_read_only_copy) { 144 CeedCallBackend(CeedCalloc(length, &impl->array_read_only_copy)); 145 memcpy(impl->array_read_only_copy, impl->array, length * sizeof(CeedScalar)); 146 } 147 *array = impl->array_read_only_copy; 148 return CEED_ERROR_SUCCESS; 149 } 150 151 //------------------------------------------------------------------------------ 152 // Vector Get Array Write 153 //------------------------------------------------------------------------------ 154 static int CeedVectorGetArrayWrite_Memcheck(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 155 CeedSize length; 156 CeedVector_Memcheck *impl; 157 158 CeedCallBackend(CeedVectorGetData(vec, &impl)); 159 CeedCallBackend(CeedVectorGetLength(vec, &length)); 160 161 // Invalidate data to make sure no read occurs 162 if (!impl->array) CeedCallBackend(CeedVectorSetArray_Memcheck(vec, mem_type, CEED_COPY_VALUES, NULL)); 163 CeedCallBackend(CeedVectorGetArray_Memcheck(vec, mem_type, array)); 164 for (CeedSize i = 0; i < length; i++) (*array)[i] = NAN; 165 impl->is_write_only_access = true; 166 return CEED_ERROR_SUCCESS; 167 } 168 169 //------------------------------------------------------------------------------ 170 // Vector Restore Array 171 //------------------------------------------------------------------------------ 172 static int CeedVectorRestoreArray_Memcheck(CeedVector vec) { 173 Ceed ceed; 174 CeedSize length; 175 CeedVector_Memcheck *impl; 176 177 CeedCallBackend(CeedVectorGetData(vec, &impl)); 178 CeedCallBackend(CeedVectorGetLength(vec, &length)); 179 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 180 181 memcpy(impl->array, impl->array_writable_copy, length * sizeof(CeedScalar)); 182 for (CeedSize i = 0; i < length; i++) impl->array_writable_copy[i] = NAN; 183 CeedCallBackend(CeedFree(&impl->array_writable_copy)); 184 if (impl->is_write_only_access) { 185 for (CeedSize i = 0; i < length; i++) { 186 if (isnan(impl->array[i])) 187 CeedDebug256(ceed, CEED_DEBUG_COLOR_WARNING, "WARNING: Vec entry %" CeedSize_FMT " is NaN after restoring write-only access", i); 188 } 189 impl->is_write_only_access = false; 190 } 191 if (impl->array_borrowed) { 192 memcpy(impl->array_borrowed, impl->array, length * sizeof(CeedScalar)); 193 } 194 if (impl->array_owned) { 195 memcpy(impl->array_owned, impl->array, length * sizeof(CeedScalar)); 196 } 197 return CEED_ERROR_SUCCESS; 198 } 199 200 //------------------------------------------------------------------------------ 201 // Vector Restore Array Read-Only 202 //------------------------------------------------------------------------------ 203 static int CeedVectorRestoreArrayRead_Memcheck(CeedVector vec) { 204 CeedSize length; 205 CeedVector_Memcheck *impl; 206 207 CeedCallBackend(CeedVectorGetData(vec, &impl)); 208 CeedCallBackend(CeedVectorGetLength(vec, &length)); 209 210 CeedCheck(!memcmp(impl->array, impl->array_read_only_copy, length * sizeof(CeedScalar)), CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 211 "Array data changed while accessed in read-only mode"); 212 213 for (CeedSize i = 0; i < length; i++) impl->array_read_only_copy[i] = NAN; 214 CeedCallBackend(CeedFree(&impl->array_read_only_copy)); 215 return CEED_ERROR_SUCCESS; 216 } 217 218 //------------------------------------------------------------------------------ 219 // Vector Destroy 220 //------------------------------------------------------------------------------ 221 static int CeedVectorDestroy_Memcheck(CeedVector vec) { 222 CeedVector_Memcheck *impl; 223 224 CeedCallBackend(CeedVectorGetData(vec, &impl)); 225 VALGRIND_DISCARD(impl->mem_block_id); 226 CeedCallBackend(CeedFree(&impl->array_allocated)); 227 CeedCallBackend(CeedFree(&impl->array_owned)); 228 CeedCallBackend(CeedFree(&impl)); 229 return CEED_ERROR_SUCCESS; 230 } 231 232 //------------------------------------------------------------------------------ 233 // Vector Create 234 //------------------------------------------------------------------------------ 235 int CeedVectorCreate_Memcheck(CeedSize n, CeedVector vec) { 236 Ceed ceed; 237 CeedVector_Memcheck *impl; 238 239 CeedCallBackend(CeedCalloc(1, &impl)); 240 CeedCallBackend(CeedVectorSetData(vec, impl)); 241 242 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 243 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasValidArray", CeedVectorHasValidArray_Memcheck)); 244 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasBorrowedArrayOfType", CeedVectorHasBorrowedArrayOfType_Memcheck)); 245 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetArray", CeedVectorSetArray_Memcheck)); 246 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "TakeArray", CeedVectorTakeArray_Memcheck)); 247 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArray", CeedVectorGetArray_Memcheck)); 248 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayRead", CeedVectorGetArrayRead_Memcheck)); 249 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayWrite", CeedVectorGetArrayWrite_Memcheck)); 250 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "RestoreArray", CeedVectorRestoreArray_Memcheck)); 251 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "RestoreArrayRead", CeedVectorRestoreArrayRead_Memcheck)); 252 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Destroy", CeedVectorDestroy_Memcheck)); 253 return CEED_ERROR_SUCCESS; 254 } 255 256 //------------------------------------------------------------------------------ 257