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