xref: /libCEED/backends/memcheck/ceed-memcheck-vector.c (revision f8608ea82c72806ce37b46314218ab211cba2735)
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