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 <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