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