MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_KokkosTuningInterface.cpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
11
12#include <string>
13#include <sstream>
14#include "Teuchos_Array.hpp"
15#include "Teuchos_OrdinalTraits.hpp"
16#include "Teuchos_CommHelpers.hpp"
17#include "Teuchos_RawParameterListHelpers.hpp"
18#include "MueLu_BaseClass.hpp"
19#include "MueLu_Exceptions.hpp"
20
21// ***********************************************************************
22/* Notional Parameterlist Structure
23 "kokkos tuning: muelu parameter mapping"
24 - "input variables" "{"Chebyshev","parallel_for"}
25 - "kokkos context id" "1" # Context ID to use, assuming you inject it onto the list
26 - "param0"
27 - "muelu parameter" "smoother: params||chebyshev: degree"
28 - "discrete range" "{1,6,1}" # (low, high, step')
29 - "initial guess" "2"
30 - "param1"
31 - "muelu parameter" "smoother: params||chebyshev: eigenvalue ratio"
32 - "continuous range" "{5.0,50.0,5.0}" # (low, high, step')
33 - "initial guess" "10.0"
34
35
36 The input variables should be handled by the tuning tool.
37 The output variable should be calculated automatically based on the types above.
38 Note: We use "||" to indicate sublists.
39 */
40
41namespace MueLu {
42
43// FIXME: Will probably need to bump this
44namespace KokkosTuningParams {
45const int MAX_VALID_PARAMS = 10;
46}
47
48// ***********************************************************************
50 : comm_(comm) {
51}
52
53// ***********************************************************************
54RCP<const Teuchos::ParameterList> KokkosTuningInterface::GetValidParameterList() const {
55 RCP<ParameterList> topValidParamList = rcp(new ParameterList());
56 ParameterList validParamList;
57
58 ParameterList pl_dummy;
59 Teuchos::Array<std::string> ar_dummy;
60 std::string s_dummy;
61
62 // Input variables for Kokkos tuning
63 validParamList.set<Teuchos::Array<std::string>>("input variables", ar_dummy, "Names of the input variables for Kokkos tuning");
64
65 validParamList.set<size_t>("kokkos context id", Teuchos::OrdinalTraits<size_t>::invalid(), "Context ID for Kokkos tuning");
66
67 for (int i = 0; i < KokkosTuningParams::MAX_VALID_PARAMS; i++) {
68 std::ostringstream oss;
69 oss << "param" << i;
70 const std::string name = oss.str();
71
72 // FIXME: Not validating parameter sublists at present
73 validParamList.set<Teuchos::ParameterList>(name, pl_dummy, "Parameter-specific sublist");
74 }
75
76 topValidParamList->set<Teuchos::ParameterList>("kokkos tuning: muelu parameter mapping", validParamList, "Sublist for Kokkos tuning of MueLu");
77
78 return topValidParamList;
79}
80
81// ***********************************************************************
83 // Sanity check
84 if (comm_.is_null()) throw std::runtime_error("MueLu::KokkosTuningInterface::Setup(): Communicator cannot be null");
85
86 // Unpack the MueLu Mapping into something actionable
88}
89
90// ***********************************************************************
92 const Teuchos::ParameterList& pL = params_.get<Teuchos::ParameterList>("kokkos tuning: muelu parameter mapping");
93 namespace KTE = Kokkos::Tools::Experimental;
94
95 /********************************/
96 /* Process the output variables */
97 /********************************/
98 out_variables.clear();
99 out_names.clear();
100
101 for (int i = 0; i < KokkosTuningParams::MAX_VALID_PARAMS; i++) {
102 std::ostringstream oss;
103 oss << "param" << i;
104 const std::string name = oss.str();
105
106 if (pL.isSublist(name)) {
107 const Teuchos::ParameterList& sublist = pL.sublist(name);
108 std::string muelu_param = sublist.get<std::string>("muelu parameter");
109
110 // Infer types from initial guess
111 if (sublist.isType<int>("initial guess")) {
112 // Discrete range
113 int guess = sublist.get<int>("initial guess");
114 const Teuchos::Array<int>& range = sublist.get<Teuchos::Array<int>>("discrete range");
115 TEUCHOS_TEST_FOR_EXCEPTION(range.size() != 3, Exceptions::RuntimeError, "MueLu::KokkosTuningInterface: 'discrete range' needs to be (low, high, step)");
116
117 // Set the VariableInfo
118 KTE::VariableInfo out_info;
119 out_info.type = KTE::ValueType::kokkos_value_int64;
120 out_info.category = KTE::StatisticalCategory::kokkos_value_interval;
121 out_info.valueQuantity = KTE::CandidateValueType::kokkos_value_range;
122
123 // Unlike the ordinal lists, the ranges get copied into Kokkos
124 // TODO: Add support for open/closed ranges
125 out_info.candidates = KTE::make_candidate_range((int64_t)range[0], (int64_t)range[1], (int64_t)range[2], false, false);
126 size_t var_id = KTE::declare_output_type(muelu_param, out_info);
127 out_variables.push_back(KTE::make_variable_value(var_id, int64_t(guess)));
128
129 out_typenames.push_back("int");
130 } else if (sublist.isType<double>("initial guess")) {
131 // Continuous range
132 double guess = sublist.get<double>("initial guess");
133 const Teuchos::Array<double>& range = sublist.get<Teuchos::Array<double>>("continuous range");
134 TEUCHOS_TEST_FOR_EXCEPTION(range.size() != 3, Exceptions::RuntimeError, "MueLu::KokkosTuningInterface: 'continuous range' needs to be (low, high, step)");
135
136 // Set the VariableInfo
137 KTE::VariableInfo out_info;
138 out_info.type = KTE::ValueType::kokkos_value_double;
139 out_info.category = KTE::StatisticalCategory::kokkos_value_interval;
140 out_info.valueQuantity = KTE::CandidateValueType::kokkos_value_range;
141
142 // Unlike the ordinal lists, the ranges get copied into Kokkos
143 // TODO: Add support for open/closed ranges
144 out_info.candidates = KTE::make_candidate_range(range[0], range[1], range[2], false, false);
145 size_t var_id = KTE::declare_output_type(muelu_param, out_info);
146 out_variables.push_back(KTE::make_variable_value(var_id, guess));
147
148 out_typenames.push_back("double");
149 }
150 // TODO: Add support for categorical and set parameters
151 else {
152 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "MueLu::KokkosTuningInterface: We currently only handle int and double ranges.");
153 }
154
155 // Stash the parameter name
156 out_names.push_back(muelu_param);
157
158 } // end if pL.isSublist
159
160 } // end for
161
162 // Sanity check
163 TEUCHOS_TEST_FOR_EXCEPTION(out_names.size() != out_variables.size(), Exceptions::RuntimeError, "MueLu::KokkosTuningInterface: Error in option processing");
164 TEUCHOS_TEST_FOR_EXCEPTION(out_names.size() != out_typenames.size(), Exceptions::RuntimeError, "MueLu::KokkosTuningInterface: Error in option processing");
165
166 /********************************/
167 /* Process the input variables */
168 /********************************/
169 in_variables.clear();
170
171 const Teuchos::Array<std::string>& inputs = pL.get<Teuchos::Array<std::string>>("input variables");
172
173 for (int i = 0; i < (int)inputs.size(); i++) {
174 // NOTE: The string name is copied in here (unlike double/int) so we don't need to cache.
175 KTE::VariableInfo in_info;
176 in_info.type = KTE::ValueType::kokkos_value_string;
177 size_t var_id = KTE::declare_input_type(inputs[i].c_str(), in_info);
178 in_variables.push_back(KTE::make_variable_value(var_id, inputs[i].c_str()));
179 }
180}
181
182// ***********************************************************************
183std::vector<std::string> KokkosTuningInterface::SplitString(const std::string& base_string, const std::string& delimiter) const {
184 std::vector<std::string> tokens;
185 size_t start = 0;
186
187 size_t end = base_string.find(delimiter);
188
189 while (end != std::string::npos) {
190 tokens.push_back(base_string.substr(start, end - start));
191 start = end + delimiter.length();
192 end = base_string.find(delimiter, start);
193 }
194
195 // And the final token...
196 tokens.push_back(base_string.substr(start, end));
197
198 return tokens;
199}
200
201// ***********************************************************************
202void KokkosTuningInterface::SetMueLuParameters(size_t kokkos_context_id, Teuchos::ParameterList& mueluParams, bool overwrite) const {
203 namespace KTE = Kokkos::Tools::Experimental;
204 Teuchos::ParameterList tunedParams;
205
206 if (comm_->getRank() == 0) {
207 // Only Rank 0 calls KokkosTuning
208 GetOStream(Runtime0) << "MueLu::KokkosTuningInterface: Tuning " << out_variables.size() << " parameters" << std::endl;
209
210 // Set input variable
211 if (IsPrint(Runtime1))
212 GetOStream(Runtime1) << "Adding " << in_variables.size() << " input variables" << std::endl;
213
214 KTE::set_input_values(kokkos_context_id, in_variables.size(), in_variables.data());
215
216 // Start the tuning
217 KTE::request_output_values(kokkos_context_id, out_variables.size(), out_variables.data());
218
219 // Diagnostic output
220 if (IsPrint(Runtime1)) {
221 GetOStream(Runtime1) << "Tuned Parameters: " << std::endl;
222 for (int i = 0; i < (int)out_variables.size(); i++) {
223 if (out_typenames[i] == "int")
224 GetOStream(Runtime1) << "- " << out_names[i] << ": " << out_variables[i].value.int_value << std::endl;
225 else if (out_typenames[i] == "double")
226 GetOStream(Runtime1) << "- " << out_names[i] << ": " << out_variables[i].value.double_value << std::endl;
227 }
228 }
229
230 // Unpack the tuned values
231 for (int i = 0; i < (int)out_names.size(); i++) {
232 // Because we'll want to set parameters inside sublists we'll allow the "muelu parameter" option to specify sublists with '||' as a nesting delimiter
233 // That's really, really unlikely to be part of a parameter list item name, so we'll go with it.
234 Teuchos::ParameterList* activeList = &tunedParams;
235 std::vector<std::string> treeWalk = SplitString(out_names[i], "||");
236
237 // Walk down all but the last guy
238 for (int j = 0; j < (int)treeWalk.size() - 1; j++) {
239 activeList = &(activeList->sublist(treeWalk[j]));
240 }
241
242 std::string activeName = treeWalk[treeWalk.size() - 1];
243
244 if (out_typenames[i] == "int")
245 activeList->set(activeName, (int)out_variables[i].value.int_value);
246 else if (out_typenames[i] == "double")
247 activeList->set(activeName, out_variables[i].value.double_value);
248 else {
249 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "MueLu::KokkosTuningInterface: Unknown variable output type");
250 }
251 }
252 }
253
254 Teuchos::updateParametersAndBroadcast(outArg(tunedParams), outArg(mueluParams), *comm_, 0, overwrite);
255}
256
257// ***********************************************************************
258void KokkosTuningInterface::SetMueLuParameters(Teuchos::ParameterList& mueluParams, bool overwrite) const {
259 size_t PL_kokkos_context_id = mueluParams.get<Teuchos::ParameterList>("kokkos tuning: muelu parameter mapping").get<size_t>("kokkos context id");
260
261 SetMueLuParameters(PL_kokkos_context_id, mueluParams, overwrite);
262}
263
264} // namespace MueLu
Exception throws to report errors in the internal logical of the program.
std::vector< Kokkos::Tools::Experimental::VariableValue > out_variables
std::vector< std::string > SplitString(const std::string &base_string, const std::string &delimiter) const
Teuchos::RCP< const Teuchos::Comm< int > > comm_
std::vector< Kokkos::Tools::Experimental::VariableValue > in_variables
Teuchos::RCP< const Teuchos::ParameterList > GetValidParameterList() const
void SetMueLuParameters(size_t kokkos_context_id, Teuchos::ParameterList &mueluParams, bool overwrite=true) const
KokkosTuningInterface(const Teuchos::RCP< const Teuchos::Comm< int > > &comm)
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
bool IsPrint(MsgType type, int thisProcRankOnly=-1) const
Find out whether we need to print out information for a specific message type.
Namespace for MueLu classes and methods.
@ Runtime0
One-liner description of what is happening.
@ Runtime1
Description of what is happening (more verbose)