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 CeedSize length; 106 CeedVector_Memcheck *impl; 107 108 CeedCallBackend(CeedVectorGetData(vec, &impl)); 109 CeedCallBackend(CeedVectorGetLength(vec, &length)); 110 111 CeedCheck(mem_type == CEED_MEM_HOST, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 112 113 CeedCallBackend(CeedCalloc(length, &impl->array_writable_copy)); 114 memcpy(impl->array_writable_copy, impl->array, length * sizeof((impl->array)[0])); 115 *array = impl->array_writable_copy; 116 return CEED_ERROR_SUCCESS; 117 } 118 119 //------------------------------------------------------------------------------ 120 // Vector Get Array Read 121 //------------------------------------------------------------------------------ 122 static int CeedVectorGetArrayRead_Memcheck(CeedVector vec, CeedMemType mem_type, const CeedScalar **array) { 123 CeedSize length; 124 CeedVector_Memcheck *impl; 125 126 CeedCallBackend(CeedVectorGetData(vec, &impl)); 127 CeedCallBackend(CeedVectorGetLength(vec, &length)); 128 129 CeedCheck(mem_type == CEED_MEM_HOST, CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, "Can only provide HOST memory for this backend"); 130 131 // Make copy to verify no write occurred 132 *array = impl->array; 133 if (!impl->array_read_only_copy) { 134 CeedCallBackend(CeedCalloc(length, &impl->array_read_only_copy)); 135 memcpy(impl->array_read_only_copy, *array, length * sizeof((*array)[0])); 136 } 137 return CEED_ERROR_SUCCESS; 138 } 139 140 //------------------------------------------------------------------------------ 141 // Vector Get Array Write 142 //------------------------------------------------------------------------------ 143 static int CeedVectorGetArrayWrite_Memcheck(CeedVector vec, CeedMemType mem_type, CeedScalar **array) { 144 CeedSize length; 145 CeedVector_Memcheck *impl; 146 147 CeedCallBackend(CeedVectorGetData(vec, &impl)); 148 CeedCallBackend(CeedVectorGetLength(vec, &length)); 149 150 // Invalidate data to make sure no read occurs 151 if (!impl->array) CeedCallBackend(CeedVectorSetArray_Memcheck(vec, mem_type, CEED_COPY_VALUES, NULL)); 152 CeedCallBackend(CeedVectorGetArray_Memcheck(vec, mem_type, array)); 153 for (CeedSize i = 0; i < length; i++) (*array)[i] = NAN; 154 impl->is_write_only_access = true; 155 return CEED_ERROR_SUCCESS; 156 } 157 158 //------------------------------------------------------------------------------ 159 // Vector Restore Array 160 //------------------------------------------------------------------------------ 161 static int CeedVectorRestoreArray_Memcheck(CeedVector vec) { 162 Ceed ceed; 163 CeedSize length; 164 CeedVector_Memcheck *impl; 165 166 CeedCallBackend(CeedVectorGetData(vec, &impl)); 167 CeedCallBackend(CeedVectorGetLength(vec, &length)); 168 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 169 170 memcpy(impl->array, impl->array_writable_copy, length * sizeof((impl->array)[0])); 171 CeedCallBackend(CeedFree(&impl->array_writable_copy)); 172 if (impl->is_write_only_access) { 173 for (CeedSize i = 0; i < length; i++) { 174 if (isnan(impl->array[i])) 175 CeedDebug256(ceed, CEED_DEBUG_COLOR_WARNING, "WARNING: Vec entry %" CeedSize_FMT " is NaN after restoring write-only access", i); 176 } 177 impl->is_write_only_access = false; 178 } 179 if (impl->array_borrowed) { 180 memcpy(impl->array_borrowed, impl->array, length * sizeof(impl->array[0])); 181 } 182 if (impl->array_owned) { 183 memcpy(impl->array_owned, impl->array, length * sizeof(impl->array[0])); 184 } 185 return CEED_ERROR_SUCCESS; 186 } 187 188 //------------------------------------------------------------------------------ 189 // Vector Restore Array Read-Only 190 //------------------------------------------------------------------------------ 191 static int CeedVectorRestoreArrayRead_Memcheck(CeedVector vec) { 192 CeedSize length; 193 CeedVector_Memcheck *impl; 194 195 CeedCallBackend(CeedVectorGetData(vec, &impl)); 196 CeedCallBackend(CeedVectorGetLength(vec, &length)); 197 198 CeedCheck(!memcmp(impl->array, impl->array_read_only_copy, length * sizeof(impl->array[0])), CeedVectorReturnCeed(vec), CEED_ERROR_BACKEND, 199 "Array data changed while accessed in read-only mode"); 200 201 CeedCallBackend(CeedFree(&impl->array_read_only_copy)); 202 return CEED_ERROR_SUCCESS; 203 } 204 205 //------------------------------------------------------------------------------ 206 // Vector Destroy 207 //------------------------------------------------------------------------------ 208 static int CeedVectorDestroy_Memcheck(CeedVector vec) { 209 CeedVector_Memcheck *impl; 210 211 CeedCallBackend(CeedVectorGetData(vec, &impl)); 212 VALGRIND_DISCARD(impl->mem_block_id); 213 CeedCallBackend(CeedFree(&impl->array_allocated)); 214 CeedCallBackend(CeedFree(&impl->array_owned)); 215 CeedCallBackend(CeedFree(&impl)); 216 return CEED_ERROR_SUCCESS; 217 } 218 219 //------------------------------------------------------------------------------ 220 // Vector Create 221 //------------------------------------------------------------------------------ 222 int CeedVectorCreate_Memcheck(CeedSize n, CeedVector vec) { 223 Ceed ceed; 224 CeedVector_Memcheck *impl; 225 226 CeedCallBackend(CeedCalloc(1, &impl)); 227 CeedCallBackend(CeedVectorSetData(vec, impl)); 228 229 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 230 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasValidArray", CeedVectorHasValidArray_Memcheck)); 231 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasBorrowedArrayOfType", CeedVectorHasBorrowedArrayOfType_Memcheck)); 232 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetArray", CeedVectorSetArray_Memcheck)); 233 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "TakeArray", CeedVectorTakeArray_Memcheck)); 234 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArray", CeedVectorGetArray_Memcheck)); 235 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayRead", CeedVectorGetArrayRead_Memcheck)); 236 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayWrite", CeedVectorGetArrayWrite_Memcheck)); 237 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "RestoreArray", CeedVectorRestoreArray_Memcheck)); 238 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "RestoreArrayRead", CeedVectorRestoreArrayRead_Memcheck)); 239 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Destroy", CeedVectorDestroy_Memcheck)); 240 return CEED_ERROR_SUCCESS; 241 } 242 243 //------------------------------------------------------------------------------ 244