xref: /libCEED/backends/memcheck/ceed-memcheck-qfunction.c (revision ed094490f53e580908aa80e9fe815a6fd76d7526)
1 // Copyright (c) 2017-2025, 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 <stdio.h>
12 #include <valgrind/memcheck.h>
13 
14 #include "ceed-memcheck.h"
15 
16 //------------------------------------------------------------------------------
17 // QFunction Apply
18 //------------------------------------------------------------------------------
19 static int CeedQFunctionApply_Memcheck(CeedQFunction qf, CeedInt Q, CeedVector *U, CeedVector *V) {
20   void                   *ctx_data = NULL;
21   int                     input_block_ids[CEED_FIELD_MAX], output_block_ids[CEED_FIELD_MAX];
22   CeedInt                 num_in, num_out;
23   CeedQFunctionUser       f = NULL;
24   CeedQFunctionField     *output_fields;
25   CeedQFunction_Memcheck *impl;
26 
27   CeedCallBackend(CeedQFunctionGetData(qf, &impl));
28   CeedCallBackend(CeedQFunctionGetContextData(qf, CEED_MEM_HOST, &ctx_data));
29   CeedCallBackend(CeedQFunctionGetUserFunction(qf, &f));
30   CeedCallBackend(CeedQFunctionGetNumArgs(qf, &num_in, &num_out));
31 
32   // Get input arrays
33   for (CeedInt i = 0; i < num_in; i++) {
34     CeedSize len;
35     char     name[32] = "";
36 
37     CeedCallBackend(CeedVectorGetArrayRead(U[i], CEED_MEM_HOST, &impl->inputs[i]));
38 
39     CeedCallBackend(CeedVectorGetLength(U[i], &len));
40 
41     snprintf(name, 32, "QFunction input %" CeedInt_FMT, i);
42     input_block_ids[i] = VALGRIND_CREATE_BLOCK(impl->inputs[i], len, name);
43   }
44 
45   // Get output arrays
46   for (CeedInt i = 0; i < num_out; i++) {
47     CeedSize len;
48     char     name[32] = "";
49 
50     CeedCallBackend(CeedVectorGetArrayWrite(V[i], CEED_MEM_HOST, &impl->outputs[i]));
51 
52     CeedCallBackend(CeedVectorGetLength(V[i], &len));
53     VALGRIND_MAKE_MEM_UNDEFINED(impl->outputs[i], len);
54 
55     snprintf(name, 32, "QFunction output %" CeedInt_FMT, i);
56     output_block_ids[i] = VALGRIND_CREATE_BLOCK(impl->outputs[i], len, name);
57   }
58 
59   // Call user function
60   CeedCallBackend(f(ctx_data, Q, impl->inputs, impl->outputs));
61 
62   // Restore input arrays
63   for (CeedInt i = 0; i < num_in; i++) {
64     CeedCallBackend(CeedVectorRestoreArrayRead(U[i], &impl->inputs[i]));
65     VALGRIND_DISCARD(input_block_ids[i]);
66   }
67 
68   // Check for unset output values and restore arrays
69   {
70     const char *kernel_name, *kernel_path;
71 
72     CeedCallBackend(CeedQFunctionGetSourcePath(qf, &kernel_path));
73     CeedCallBackend(CeedQFunctionGetKernelName(qf, &kernel_name));
74     CeedCallBackend(CeedQFunctionGetFields(qf, NULL, NULL, NULL, &output_fields));
75     for (CeedInt i = 0; i < num_out; i++) {
76       const char *field_name;
77       CeedInt     field_size;
78 
79       // Note: need field size because vector may be longer than needed for output
80       CeedCallBackend(CeedQFunctionFieldGetSize(output_fields[i], &field_size));
81       CeedCallBackend(CeedQFunctionFieldGetName(output_fields[i], &field_name));
82       for (CeedSize j = 0; j < field_size * (CeedSize)Q; j++) {
83         CeedCheck(!isnan(impl->outputs[i][j]), CeedQFunctionReturnCeed(qf), CEED_ERROR_BACKEND,
84                   "QFunction output %" CeedInt_FMT " '%s' entry %" CeedSize_FMT " is NaN after restoring write-only access: %s:%s ", i, field_name, j,
85                   kernel_path, kernel_name);
86       }
87       CeedCallBackend(CeedVectorRestoreArray(V[i], &impl->outputs[i]));
88       VALGRIND_DISCARD(output_block_ids[i]);
89     }
90   }
91   CeedCallBackend(CeedQFunctionRestoreContextData(qf, &ctx_data));
92   return CEED_ERROR_SUCCESS;
93 }
94 
95 //------------------------------------------------------------------------------
96 // QFunction Destroy
97 //------------------------------------------------------------------------------
98 static int CeedQFunctionDestroy_Memcheck(CeedQFunction qf) {
99   CeedQFunction_Memcheck *impl;
100 
101   CeedCallBackend(CeedQFunctionGetData(qf, &impl));
102   CeedCallBackend(CeedFree(&impl->inputs));
103   CeedCallBackend(CeedFree(&impl->outputs));
104   CeedCallBackend(CeedFree(&impl));
105   return CEED_ERROR_SUCCESS;
106 }
107 
108 //------------------------------------------------------------------------------
109 // QFunction Create
110 //------------------------------------------------------------------------------
111 int CeedQFunctionCreate_Memcheck(CeedQFunction qf) {
112   Ceed                    ceed;
113   CeedQFunction_Memcheck *impl;
114 
115   CeedCallBackend(CeedQFunctionGetCeed(qf, &ceed));
116   CeedCallBackend(CeedCalloc(1, &impl));
117   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->inputs));
118   CeedCallBackend(CeedCalloc(CEED_FIELD_MAX, &impl->outputs));
119   CeedCallBackend(CeedQFunctionSetData(qf, impl));
120   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunction", qf, "Apply", CeedQFunctionApply_Memcheck));
121   CeedCallBackend(CeedSetBackendFunction(ceed, "QFunction", qf, "Destroy", CeedQFunctionDestroy_Memcheck));
122   CeedCallBackend(CeedDestroy(&ceed));
123   return CEED_ERROR_SUCCESS;
124 }
125 
126 //------------------------------------------------------------------------------
127