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])) CeedDebug256(ceed, CEED_DEBUG_COLOR_WARNING, "WARNING: Vec entry %ld is NaN after restoring write-only access", i); 180 } 181 impl->is_write_only_access = false; 182 } 183 if (impl->array_borrowed) { 184 memcpy(impl->array_borrowed, impl->array, length * sizeof(impl->array[0])); 185 } 186 if (impl->array_owned) { 187 memcpy(impl->array_owned, impl->array, length * sizeof(impl->array[0])); 188 } 189 return CEED_ERROR_SUCCESS; 190 } 191 192 //------------------------------------------------------------------------------ 193 // Vector Restore Array Read-Only 194 //------------------------------------------------------------------------------ 195 static int CeedVectorRestoreArrayRead_Memcheck(CeedVector vec) { 196 Ceed ceed; 197 CeedSize length; 198 CeedVector_Memcheck *impl; 199 200 CeedCallBackend(CeedVectorGetData(vec, &impl)); 201 CeedCallBackend(CeedVectorGetLength(vec, &length)); 202 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 203 204 CeedCheck(!memcmp(impl->array, impl->array_read_only_copy, length * sizeof(impl->array[0])), ceed, CEED_ERROR_BACKEND, 205 "Array data changed while accessed in read-only mode"); 206 207 CeedCallBackend(CeedFree(&impl->array_read_only_copy)); 208 return CEED_ERROR_SUCCESS; 209 } 210 211 //------------------------------------------------------------------------------ 212 // Vector Destroy 213 //------------------------------------------------------------------------------ 214 static int CeedVectorDestroy_Memcheck(CeedVector vec) { 215 CeedVector_Memcheck *impl; 216 217 CeedCallBackend(CeedVectorGetData(vec, &impl)); 218 VALGRIND_DISCARD(impl->mem_block_id); 219 CeedCallBackend(CeedFree(&impl->array_allocated)); 220 CeedCallBackend(CeedFree(&impl->array_owned)); 221 CeedCallBackend(CeedFree(&impl)); 222 return CEED_ERROR_SUCCESS; 223 } 224 225 //------------------------------------------------------------------------------ 226 // Vector Create 227 //------------------------------------------------------------------------------ 228 int CeedVectorCreate_Memcheck(CeedSize n, CeedVector vec) { 229 Ceed ceed; 230 CeedVector_Memcheck *impl; 231 232 CeedCallBackend(CeedCalloc(1, &impl)); 233 CeedCallBackend(CeedVectorSetData(vec, impl)); 234 235 CeedCallBackend(CeedVectorGetCeed(vec, &ceed)); 236 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasValidArray", CeedVectorHasValidArray_Memcheck)); 237 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "HasBorrowedArrayOfType", CeedVectorHasBorrowedArrayOfType_Memcheck)); 238 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "SetArray", CeedVectorSetArray_Memcheck)); 239 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "TakeArray", CeedVectorTakeArray_Memcheck)); 240 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArray", CeedVectorGetArray_Memcheck)); 241 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayRead", CeedVectorGetArrayRead_Memcheck)); 242 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "GetArrayWrite", CeedVectorGetArrayWrite_Memcheck)); 243 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "RestoreArray", CeedVectorRestoreArray_Memcheck)); 244 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "RestoreArrayRead", CeedVectorRestoreArrayRead_Memcheck)); 245 CeedCallBackend(CeedSetBackendFunction(ceed, "Vector", vec, "Destroy", CeedVectorDestroy_Memcheck)); 246 return CEED_ERROR_SUCCESS; 247 } 248 249 //------------------------------------------------------------------------------ 250