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