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