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