Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_SystemInformation.cpp
1// @HEADER
2// *****************************************************************************
3// Teuchos: Common Tools Package
4//
5// Copyright 2004 NTESS and the Teuchos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
11#include "Teuchos_EnvVariables.hpp"
12#include "Teuchos_StrUtils.hpp"
14
15#if !defined(__GNUC__) || (__GNUC__ >= 10)
16#include <filesystem>
17#endif
18#include <iostream>
19#include <stdexcept>
20#include <set>
21
22// environ should be available on posix platforms
23#if not(defined(WIN) && (_MSC_VER >= 1900))
24// needs to be in the global namespace
25extern char **environ;
26#endif
27
28namespace Teuchos::SystemInformation {
29
30namespace {
31
32std::map<std::string, std::pair<std::string, std::string>>& getCommandsMap() {
33 static std::map<std::string, std::pair<std::string, std::string>> commands;
34 return commands;
35}
36
37std::set<std::string>& getEnvironmentVariablesSet() {
38 static std::set<std::string> environmentVariables;
39 return environmentVariables;
40}
41
42std::set<std::string>& getEnvironmentVariablePrefixSet() {
43 static std::set<std::string> environmentVariablePrefixes;
44 return environmentVariablePrefixes;
45}
46
47
48}
49
50bool commandIsAvailable(const std::string &command) {
51 return !std::system(
52 std::string("command -v " + command + " > /dev/null 2>&1").c_str());
53}
54
55std::string runCommandAndCaptureOutput(const std::string &command) {
56 char buffer[128];
57 std::string result = "";
58 FILE *pipe = popen(command.c_str(), "r");
59 if (!pipe)
60 return "command \"" + command + "\"failed";
61 try {
62 while (fgets(buffer, sizeof buffer, pipe) != NULL) {
63 result += buffer;
64 }
65 } catch (...) {
66 pclose(pipe);
67 return "command \"" + command + "\"failed";
68 }
69 pclose(pipe);
70 return result;
71}
72
73RegistrationResult
74registerEnvironmentVariable(const std::string &variableName) {
75 auto &environmentVariables = getEnvironmentVariablesSet();
76
77 if (auto search = environmentVariables.find(variableName);
78 search != environmentVariables.end()) {
79 // variable is already present
80 return ALREADY_PRESENT;
81 } else {
82 // variable not found
83 environmentVariables.insert(variableName);
84 return REGISTERED;
85 }
86}
87
88void registerAllPrefixedVariables(const std::string &prefix) {
89 char **env;
90#if defined(WIN) && (_MSC_VER >= 1900)
91 env = *__p__environ();
92#else
93 env = environ; // defined at the top of this file as extern char **environ;
94#endif
95 for (; *env; ++env) {
96 // const std::string_view ev(*env);
97
98 // split name=value on the first =, everything before = is name
99 auto substrings = StrUtils::splitString(*env, '=');
100 if (substrings.size() > 0) {
101 std::string name = substrings[0];
102
103 if (name.size() >= prefix.size() &&
104 name.substr(0, prefix.size()) == prefix) {
105 Teuchos::SystemInformation::registerEnvironmentVariable(name);
106 }
107 }
108 }
109}
110
111RegistrationResult
112registerEnvironmentVariablePrefix(const std::string &prefix) {
113 auto &environmentVariablePrefixes = getEnvironmentVariablePrefixSet();
114 if (auto search = environmentVariablePrefixes.find(prefix);
115 search != environmentVariablePrefixes.end()) {
116 // variable is already present
117 return ALREADY_PRESENT;
118 } else {
119 // variable not found
120 environmentVariablePrefixes.insert(prefix);
121 return REGISTERED;
122 }
123
124}
125
126RegistrationResult
127registerCommand(const std::string &commandLabel,
128 const std::string &commandToRunAndCapture,
129 const std::string &commandToCheckForExistence) {
130 auto &commands = getCommandsMap();
131
132 std::string myCommandToRunAndCapture = commandToRunAndCapture;
133 if (myCommandToRunAndCapture.empty())
134 myCommandToRunAndCapture = commandLabel;
135
136 std::string myCommandToCheckForExistence = commandToCheckForExistence;
137 if (myCommandToCheckForExistence.empty())
138 myCommandToCheckForExistence = myCommandToRunAndCapture;
139
140 if (auto search = commands.find(commandLabel); search != commands.end()) {
141 if ((commands[commandLabel].first == myCommandToCheckForExistence) &&
142 (commands[commandLabel].second == myCommandToRunAndCapture))
143 return ALREADY_PRESENT;
144 else {
145 std::cerr
146 << "Teuchos::SystemInformation: Attempted to register a command (\""
147 << commandLabel << "\", \"" << myCommandToRunAndCapture << "\", \""
148 << myCommandToCheckForExistence << "\") "
149 << "that clashes with already registered command: (" << commandLabel
150 << "\", \"" << commands[commandLabel].first << "\", \""
151 << commands[commandLabel].second << "\")." << std::endl;
152 return FAILURE;
153 }
154 } else {
155 // command not found
156 commands[commandLabel] = {myCommandToCheckForExistence, myCommandToRunAndCapture};
157 return REGISTERED;
158 }
159}
160
161void initializeCollection() {
162
163 std::string userProvidedEnvVariables =
165 "TEUCHOS_USER_ENVIRONMENT_VARIABLES", "");
166 if (!userProvidedEnvVariables.empty()) {
167 auto strings = StrUtils::splitString(userProvidedEnvVariables, ';');
168 bool isValid = (strings.size() >= 1);
169 if (!isValid)
170 std::cerr
171 << "Teuchos::SystemInformation: The value of the environment "
172 "variable "
173 "TEUCHOS_USER_ENVIRONMENT_VARIABLES needs to be a semi-colon "
174 "seperated string. Value: "
175 << userProvidedEnvVariables << std::endl;
176 for (int itemNo = 0; itemNo < strings.size(); ++itemNo) {
177 std::string &variableName = strings[itemNo];
178 if (registerEnvironmentVariable(variableName) == FAILURE)
179 isValid = false;
180 }
182 !isValid, std::runtime_error,
183 "Teuchos::SystemInformation: Invalid environment variable "
184 "TEUCHOS_USER_ENVIRONMENT_VARIABLES");
185 }
186
187 std::string userProvidedCommands =
188 Teuchos::getEnvironmentVariable<std::string>("TEUCHOS_USER_COMMANDS", "");
189 if (!userProvidedCommands.empty()) {
190 auto strings = StrUtils::splitString(userProvidedEnvVariables, ';');
191 bool isValid = (strings.size() % 3 == 0) && (strings.size() >= 3);
192 if (!isValid)
193 std::cerr << "Teuchos::SystemInformation: The value of the environment "
194 "variable TEUCHOS_USER_COMMANDS "
195 "needs to be a semi-colon seperated string with a number of "
196 "elements that is a multiple of 3. Value: "
197 << userProvidedCommands << std::endl;
198 int tupleNo = 0;
199 while (isValid && (3 * tupleNo + 2 < strings.size())) {
200 std::string &commandLabel = strings[3 * tupleNo];
201 std::string &commandToRunAndCapture = strings[3 * tupleNo + 1];
202 std::string &commandToCheckForExistence = strings[3 * tupleNo + 2];
203 if (registerCommand(commandLabel, commandToRunAndCapture,
204 commandToCheckForExistence) == FAILURE) {
205 isValid = false;
206 }
207 ++tupleNo;
208 }
209 TEUCHOS_TEST_FOR_EXCEPTION(!isValid, std::runtime_error,
210 "Teuchos::SystemInformation: Invalid "
211 "environment variable TEUCHOS_USER_COMMANDS");
212 }
213
214#if !defined(__GNUC__) || (__GNUC__ >= 10)
215 try {
216 const std::string executable = std::filesystem::canonical("/proc/self/exe");
217 if (!executable.empty()) {
218 registerCommand("ldd", "ldd " + executable, "ldd");
219 }
220 } catch (std::filesystem::filesystem_error &) {
221 // ignore
222 }
223#endif
224
225 // CPUs
226 registerCommand("lscpu");
227
228 // temperature sensore
229 registerCommand("sensors");
230
231 // OpenMP
232 registerEnvironmentVariablePrefix("OMP");
233
234 // OpenMPI
235 registerCommand("ompi_info");
236 registerEnvironmentVariablePrefix("OMPI");
237
238 // MPICH
239 registerCommand("mpichinfo");
240 registerEnvironmentVariablePrefix("MPICH");
241
242 // CRAY
243 registerEnvironmentVariablePrefix("CRAY");
244
245 // modules
246 registerCommand("module", "module list 2>&1", "module");
247
248 // CUDA
249 registerCommand("nvidia-smi", "nvidia-smi --query", "nvidia-smi");
250 registerEnvironmentVariablePrefix("CUDA");
251
252 // ROCm
253 registerCommand("rocm-smi", "rocm-smi --showallinfo", "rocm-smi");
254
255 // SYCL
256 registerCommand("sycl-ls", "sycl-ls --verbose", "sycl-ls");
257
258 // package namespaced environment variables
259 for (auto &prefix : {"TEUCHOS", "KOKKOS", "TPETRA", "STK"})
260 registerEnvironmentVariablePrefix(prefix);
261}
262
263std::map<std::string, std::string> collectSystemInformation() {
264
265 std::map<std::string, std::string> data;
266
267 const std::string DATA_NOT_AVAILABLE = "NOT AVAILABLE";
268
269 auto &commands = getCommandsMap();
270 for (auto &command : commands) {
271 const bool isAvailable = commandIsAvailable(command.second.first);
272 if (isAvailable) {
273 data[command.first] = runCommandAndCaptureOutput(command.second.second);
274 } else {
275 data[command.first] = DATA_NOT_AVAILABLE;
276 }
277 }
278
279 auto &environmentVariablePrefixes = getEnvironmentVariablePrefixSet();
280 for (auto &prefix : environmentVariablePrefixes) {
281 registerAllPrefixedVariables(prefix);
282 }
283
284 auto &environmentVariables = getEnvironmentVariablesSet();
285 for (auto &envVariable : environmentVariables) {
286 const char *varVal = std::getenv(envVariable.c_str());
287 if (varVal == nullptr)
288 data[envVariable] = "NOT SET";
289 else {
290 data[envVariable] =
292 }
293 }
294
295 return data;
296}
297
298} // namespace Teuchos::SystemInformation
A std::string utilities class for Teuchos.
Collect information about the runtime environment.
Standard test and throw macros.
Smart reference counting pointer class for automatic garbage collection.
static Array< std::string > splitString(const std::string_view s, const char sep=',')
Split an input std::string using a seperator char sep.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.