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