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