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