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 CeedCheck(mem_type == CEED_MEM_HOST, ceed, CEED_ERROR_BACKEND, "Can only set HOST memory for this backend"); 64 65 CeedCallBackend(CeedFree(&impl->array_allocated)); 66 CeedCallBackend(CeedFree(&impl->array_owned)); 67 switch (copy_mode) { 68 case CEED_COPY_VALUES: 69 CeedCallBackend(CeedCalloc(length, &impl->array_owned)); 70 impl->array_borrowed = NULL; 71 impl->array = impl->array_owned; 72 if (array) { 73 memcpy(impl->array, array, length * sizeof(array[0])); 74 } else { 75 for (CeedInt i = 0; i < length; i++) impl->array[i] = NAN; 76 } 77 break; 78 case CEED_OWN_POINTER: 79 impl->array_owned = array; 80 impl->array_borrowed = NULL; 81 impl->array = array; 82 break; 83 case CEED_USE_POINTER: 84 impl->array_borrowed = array; 85 impl->array = array; 86 } 87 // Copy data to check access 88 CeedCallBackend(CeedCalloc(length, &impl->array_allocated)); 89 memcpy(impl->array_allocated, impl->array, length * sizeof(array[0])); 90 impl->array = impl->array_allocated; 91 VALGRIND_DISCARD(impl->mem_block_id); 92 impl->mem_block_id = VALGRIND_CREATE_BLOCK(impl->array, length * sizeof(array[0]), "'Vector backend array data copy'"); 93 94 return CEED_ERROR_SUCCESS; 95 } 96 97 //------------------------------------------------------------------------------ 98 // Vector Take Array 99 //------------------------------------------------------------------------------ 100 static int CeedVectorTakeArray_Memcheck(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 101 CeedVector_Memcheck *impl; 102 CeedCallBackend(CeedVectorGetData(vec, &impl)); 103 Ceed ceed; 104 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 105 106 CeedCheck(mem_type == CEED_MEM_HOST, ceed, CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 107 108 (*array) = impl->array_borrowed; 109 impl->array_borrowed = NULL; 110 impl->array = NULL; 111 VALGRIND_DISCARD(impl->mem_block_id); 112 CeedCallBackend(CeedFree(&impl->array_allocated)); 113 114 return CEED_ERROR_SUCCESS; 115 } 116 117 //------------------------------------------------------------------------------ 118 // Vector Get Array 119 //------------------------------------------------------------------------------ 120 static int CeedVectorGetArray_Memcheck(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 121 CeedVector_Memcheck *impl; 122 CeedCallBackend(CeedVectorGetData(vec, &impl)); 123 Ceed ceed; 124 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 125 126 CeedCheck(mem_type == CEED_MEM_HOST, ceed, CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 127 128 *array = impl->array; 129 130 return CEED_ERROR_SUCCESS; 131 } 132 133 //------------------------------------------------------------------------------ 134 // Vector Get Array Read 135 //------------------------------------------------------------------------------ 136 static int CeedVectorGetArrayRead_Memcheck(CeedVector vec, CeedMemType mem_type, const CeedScalar **array) { 137 CeedVector_Memcheck *impl; 138 CeedCallBackend(CeedVectorGetData(vec, &impl)); 139 CeedSize length; 140 CeedCallBackend(CeedVectorGetLength(vec, &length)); 141 Ceed ceed; 142 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 143 144 CeedCallBackend(CeedVectorGetArray_Memcheck(vec, mem_type, (CeedScalar **)array)); 145 146 // Make copy to verify no write occurred 147 if (!impl->array_read_only_copy) { 148 CeedCallBackend(CeedCalloc(length, &impl->array_read_only_copy)); 149 memcpy(impl->array_read_only_copy, *array, length * sizeof((*array)[0])); 150 } 151 152 return CEED_ERROR_SUCCESS; 153 } 154 155 //------------------------------------------------------------------------------ 156 // Vector Get Array Write 157 //------------------------------------------------------------------------------ 158 static int CeedVectorGetArrayWrite_Memcheck(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 159 CeedVector_Memcheck *impl; 160 CeedCallBackend(CeedVectorGetData(vec, &impl)); 161 CeedSize length; 162 CeedCallBackend(CeedVectorGetLength(vec, &length)); 163 Ceed ceed; 164 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 165 166 // Invalidate data to make sure no read occurs 167 if (!impl->array) CeedCallBackend(CeedVectorSetArray_Memcheck(vec, mem_type, CEED_COPY_VALUES, NULL)); 168 CeedCallBackend(CeedVectorGetArray_Memcheck(vec, mem_type, array)); 169 for (CeedSize i = 0; i < length; i++) (*array)[i] = NAN; 170 impl->is_write_only_access = true; 171 172 return CEED_ERROR_SUCCESS; 173 } 174 175 //------------------------------------------------------------------------------ 176 // Vector Restore Array 177 //------------------------------------------------------------------------------ 178 static int CeedVectorRestoreArray_Memcheck(CeedVector vec) { 179 CeedVector_Memcheck *impl; 180 CeedCallBackend(CeedVectorGetData(vec, &impl)); 181 CeedSize length; 182 CeedCallBackend(CeedVectorGetLength(vec, &length)); 183 Ceed ceed; 184 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 185 186 if (impl->is_write_only_access) { 187 for (CeedSize i = 0; i < length; i++) { 188 if (isnan(impl->array[i])) CeedDebug256(ceed, CEED_DEBUG_COLOR_WARNING, "WARNING: Vec entry %ld is NaN after restoring write-only access", i); 189 } 190 impl->is_write_only_access = false; 191 } 192 if (impl->array_borrowed) { 193 memcpy(impl->array_borrowed, impl->array, length * sizeof(impl->array[0])); 194 } 195 if (impl->array_owned) { 196 memcpy(impl->array_owned, impl->array, length * sizeof(impl->array[0])); 197 } 198 199 return CEED_ERROR_SUCCESS; 200 } 201 202 //------------------------------------------------------------------------------ 203 // Vector Restore Array Read-Only 204 //------------------------------------------------------------------------------ 205 static int CeedVectorRestoreArrayRead_Memcheck(CeedVector vec) { 206 CeedVector_Memcheck *impl; 207 CeedCallBackend(CeedVectorGetData(vec, &impl)); 208 CeedSize length; 209 CeedCallBackend(CeedVectorGetLength(vec, &length)); 210 Ceed ceed; 211 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 212 213 CeedCheck(!memcmp(impl->array, impl->array_read_only_copy, length * sizeof(impl->array[0])), ceed, CEED_ERROR_BACKEND, 214 "Array data changed while accessed in read-only mode"); 215 216 CeedCallBackend(CeedFree(&impl->array_read_only_copy)); 217 218 return CEED_ERROR_SUCCESS; 219 } 220 221 //------------------------------------------------------------------------------ 222 // Vector Destroy 223 //------------------------------------------------------------------------------ 224 static int CeedVectorDestroy_Memcheck(CeedVector vec) { 225 CeedVector_Memcheck *impl; 226 CeedCallBackend(CeedVectorGetData(vec, &impl)); 227 228 VALGRIND_DISCARD(impl->mem_block_id); 229 CeedCallBackend(CeedFree(&impl->array_allocated)); 230 CeedCallBackend(CeedFree(&impl->array_owned)); 231 CeedCallBackend(CeedFree(&impl)); 232 return CEED_ERROR_SUCCESS; 233 } 234 235 //------------------------------------------------------------------------------ 236 // Vector Create 237 //------------------------------------------------------------------------------ 238 int CeedVectorCreate_Memcheck(CeedSize n, CeedVector vec) { 239 CeedVector_Memcheck *impl; 240 Ceed ceed; 241 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 242 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 254 CeedCallBackend(CeedCalloc(1, &impl)); 255 CeedCallBackend(CeedVectorSetData(vec, impl)); 256 257 return CEED_ERROR_SUCCESS; 258 } 259 260 //------------------------------------------------------------------------------ 261