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