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