5bc35a7eb6
* Add environment variable configuration infrastructure
- Namespace rocshmem::envvar
- Track all config env vars in per-category lists
- Remove duplicates from list of allowed env var types
- Reject negative inputs for unsigned integer types
- Accept empty strings for std::string
- Print error source location using C++20 std::source_location
- Unit tests
* Port environment variables
- ROCSHMEM_UNIQUEID_WITH_MPI
- ROCSHMEM_RO_DISABLE_IPC
- ROCSHMEM_BOOTSTRAP_TIMEOUT
- ROCSHMEM_BOOTSTRAP_HOSTID
- ROCSHMEM_BOOTSTRAP_SOCKET_IFNAME
- ROCSHMEM_RO_PROGRESS_DELAY
- ROCSHMEM_BOOTSTRAP_SOCKET_FAMILY
- ROCSHMEM_MAX_NUM_CONTEXTS
+ Merge the independent per-backend copies into a single variable
that is used by all three backends (IPC, RO, GDA).
+ Set default to 32 (for GDA); prior default for IPC and RO was 1024.
- ROCSHMEM_MAX_NUM_HOST_CONTEXTS
- ROCSHMEM_MAX_WF_BUFFERS
- ROCSHMEM_SQ_SIZE
- ROCSHMEM_RO_NET_CPU_QUEUE
+ Renamed from RO_NET_CPU_QUEUE
+ Change env var input type to bool, default to false
+ Invert code logic: setting RO_NET_CPU_QUEUE to anything
would /disable/ a variable gpu_queue, which defaulted to true.
Variable is now named config::ro::net_cpu_queue,
with all prior checks for gpu_queue inverted.
- ROCSHMEM_USE_IB_HCA
- ROCSHMEM_HEAP_SIZE
+ Defaults to 1L << 30 i.e. 1 GiB,
from default heap size in memory/heap_memory.hpp.
- ROCSHMEM_MAX_NUM_TEAMS
+ Unlike other env vars, this can be referenced from devices.
+ Function currently narrows from size_t to int: uses need to be audited
for safety and correctness in using size_t directly.
- ROCSHMEM_GDA_ALTERNATE_QP_PORTS
* New env var ROCSHMEM_DEBUG
- Debug levels:
+ NONE
+ VERSION
+ WARN
+ INFO
+ TRACE
- Currently unused - will be added later
- Mirrors RCCL debug control
* Remove rocshmem::rocshmem_env_config
* Change interface for GetClosestNicToGpu
to accept const char** instead of char**:
the pointed-to string does not need to be modified
- Files were not audited for inclusion of util.hpp only for env vars
---------
Signed-off-by: Omri Mor <Omri.Mor@amd.com>
[ROCm/rocshmem commit: a0fcbf8d35]
278 lines
8.0 KiB
C++
278 lines
8.0 KiB
C++
/******************************************************************************
|
|
* Copyright (c) Microsoft Corporation.
|
|
* Modifications Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
* IN THE SOFTWARE.
|
|
*****************************************************************************/
|
|
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
|
|
#include <chrono>
|
|
#include <cstring>
|
|
#include <fstream>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <iostream>
|
|
|
|
#include "envvar.hpp"
|
|
#include "utils.hpp"
|
|
#include "util.hpp"
|
|
|
|
constexpr char HOSTID_FILE[32] = "/proc/sys/kernel/random/boot_id";
|
|
|
|
static bool matchIf(const char* string, const char* ref, bool matchExact) {
|
|
// Make sure to include '\0' in the exact case
|
|
int matchLen = matchExact ? strlen(string) + 1 : strlen(ref);
|
|
return strncmp(string, ref, matchLen) == 0;
|
|
}
|
|
|
|
static bool matchPort(const int port1, const int port2) {
|
|
if (port1 == -1) return true;
|
|
if (port2 == -1) return true;
|
|
if (port1 == port2) return true;
|
|
return false;
|
|
}
|
|
|
|
namespace rocshmem {
|
|
|
|
std::string int64ToBusId(int64_t id) {
|
|
char busId[20];
|
|
std::snprintf(busId, sizeof(busId), "%04lx:%02lx:%02lx.%01lx", (id) >> 20, (id & 0xff000) >> 12, (id & 0xff0) >> 4,
|
|
(id & 0xf));
|
|
return std::string(busId);
|
|
}
|
|
|
|
int64_t busIdToInt64(const std::string busId) {
|
|
char hexStr[17]; // Longest possible int64 hex string + null terminator.
|
|
size_t hexOffset = 0;
|
|
for (size_t i = 0; hexOffset < sizeof(hexStr) - 1 && i < busId.length(); ++i) {
|
|
char c = busId[i];
|
|
if (c == '.' || c == ':') continue;
|
|
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
|
|
hexStr[hexOffset++] = busId[i];
|
|
} else
|
|
break;
|
|
}
|
|
hexStr[hexOffset] = '\0';
|
|
return std::strtol(hexStr, NULL, 16);
|
|
}
|
|
|
|
uint64_t getHash(const char* string, int n) {
|
|
// Based on DJB2a, result = result * 33 ^ char
|
|
uint64_t result = 5381;
|
|
for (int c = 0; c < n; c++) {
|
|
result = ((result << 5) + result) ^ string[c];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* Generate a hash of the unique identifying string for this host
|
|
* that will be unique for both bare-metal and container instances
|
|
* Equivalent of a hash of;
|
|
*
|
|
* $(hostname)$(cat /proc/sys/kernel/random/boot_id)
|
|
*
|
|
* This string can be overridden by using the ROCSHMEM_HOSTID env var.
|
|
*/
|
|
uint64_t computeHostHash(void) {
|
|
const size_t hashLen = 1024;
|
|
char hostHash[hashLen];
|
|
|
|
memset(hostHash, 0, hashLen);
|
|
|
|
std::string hostName = getHostName(hashLen, '\0');
|
|
strncpy(hostHash, hostName.c_str(), hostName.size());
|
|
|
|
const std::string& hostid = envvar::bootstrap::hostid;
|
|
if (!hostid.empty()) {
|
|
strncpy(hostHash, hostid.c_str(), hashLen);
|
|
} else if (hostName.size() < hashLen) {
|
|
std::ifstream file(HOSTID_FILE, std::ios::binary);
|
|
if (file.is_open()) {
|
|
file.read(hostHash + hostName.size(), hashLen - hostName.size());
|
|
}
|
|
}
|
|
|
|
// Make sure the string is terminated
|
|
hostHash[sizeof(hostHash) - 1] = '\0';
|
|
DPRINTF("unique hostname '%s'", hostHash);
|
|
return getHash(hostHash, strlen(hostHash));
|
|
}
|
|
|
|
uint64_t getHostHash(void) {
|
|
thread_local std::unique_ptr<uint64_t> hostHash = std::make_unique<uint64_t>(computeHostHash());
|
|
// avoid crash on static destruction
|
|
if (hostHash == nullptr) {
|
|
hostHash = std::make_unique<uint64_t>(computeHostHash());
|
|
}
|
|
return *hostHash;
|
|
}
|
|
|
|
/* Generate a hash of the unique identifying string for this process
|
|
* that will be unique for both bare-metal and container instances
|
|
* Equivalent of a hash of;
|
|
*
|
|
* $$ $(readlink /proc/self/ns/pid)
|
|
*/
|
|
uint64_t computePidHash(void) {
|
|
char pname[1024];
|
|
// Start off with our pid ($$)
|
|
std::snprintf(pname, sizeof(pname), "%ld", (long)getpid());
|
|
int plen = strlen(pname);
|
|
int len = readlink("/proc/self/ns/pid", pname + plen, sizeof(pname) - 1 - plen);
|
|
if (len < 0) len = 0;
|
|
|
|
pname[plen + len] = '\0';
|
|
DPRINTF("unique PID '%s'", pname);
|
|
|
|
return getHash(pname, strlen(pname));
|
|
}
|
|
|
|
uint64_t getPidHash(void) {
|
|
thread_local std::unique_ptr<uint64_t> pidHash = std::make_unique<uint64_t>(computePidHash());
|
|
// avoid crash on static destruction
|
|
if (pidHash == nullptr) {
|
|
pidHash = std::make_unique<uint64_t>(computePidHash());
|
|
}
|
|
return *pidHash;
|
|
}
|
|
|
|
int parseStringList(const char* string, netIf* ifList, int maxList) {
|
|
if (!string) return 0;
|
|
|
|
const char* ptr = string;
|
|
|
|
int ifNum = 0;
|
|
int ifC = 0;
|
|
char c;
|
|
do {
|
|
c = *ptr;
|
|
if (c == ':') {
|
|
if (ifC > 0) {
|
|
ifList[ifNum].prefix[ifC] = '\0';
|
|
ifList[ifNum].port = atoi(ptr + 1);
|
|
ifNum++;
|
|
ifC = 0;
|
|
}
|
|
while (c != ',' && c != '\0') c = *(++ptr);
|
|
} else if (c == ',' || c == '\0') {
|
|
if (ifC > 0) {
|
|
ifList[ifNum].prefix[ifC] = '\0';
|
|
ifList[ifNum].port = -1;
|
|
ifNum++;
|
|
ifC = 0;
|
|
}
|
|
} else {
|
|
ifList[ifNum].prefix[ifC] = c;
|
|
ifC++;
|
|
}
|
|
ptr++;
|
|
} while (ifNum < maxList && c);
|
|
return ifNum;
|
|
}
|
|
|
|
bool matchIfList(const char* string, int port, netIf* ifList, int listSize, bool matchExact) {
|
|
// Make an exception for the case where no user list is defined
|
|
if (listSize == 0) return true;
|
|
|
|
for (int i = 0; i < listSize; i++) {
|
|
if (matchIf(string, ifList[i].prefix, matchExact) && matchPort(port, ifList[i].port)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* get any bytes of random data from /dev/urandom */
|
|
void getRandomData(void* buffer, size_t bytes) {
|
|
if (bytes > 0) {
|
|
const size_t one = 1UL;
|
|
FILE* fp = fopen("/dev/urandom", "r");
|
|
if (buffer == NULL || fp == NULL || fread(buffer, bytes, one, fp) != one) {
|
|
ERROR("Failed to read random data\n");
|
|
return;
|
|
}
|
|
if (fp) fclose(fp);
|
|
}
|
|
}
|
|
|
|
} // namespace rocshmem
|
|
|
|
// Throw upon SIGALRM.
|
|
static void sigalrmTimeoutHandler(int) {
|
|
signal(SIGALRM, SIG_IGN);
|
|
//throw mscclpp::Error("Timer timed out", ErrorCode::Timeout);
|
|
ERROR("Timer timed out\n");
|
|
return;
|
|
}
|
|
|
|
namespace rocshmem {
|
|
|
|
Timer::Timer(int timeout) { set(timeout); }
|
|
|
|
Timer::~Timer() {
|
|
if (timeout_ > 0) {
|
|
alarm(0);
|
|
signal(SIGALRM, SIG_DFL);
|
|
}
|
|
}
|
|
|
|
int64_t Timer::elapsed() const {
|
|
auto end = std::chrono::steady_clock::now();
|
|
return std::chrono::duration_cast<std::chrono::microseconds>(end - start_).count();
|
|
}
|
|
|
|
void Timer::set(int timeout) {
|
|
timeout_ = timeout;
|
|
if (timeout > 0) {
|
|
signal(SIGALRM, sigalrmTimeoutHandler);
|
|
alarm(timeout);
|
|
}
|
|
start_ = std::chrono::steady_clock::now();
|
|
}
|
|
|
|
void Timer::reset() { set(timeout_); }
|
|
|
|
void Timer::print(const std::string& name) {
|
|
auto us = elapsed();
|
|
printf("%s : %ld\n", name.c_str(), us);
|
|
}
|
|
|
|
ScopedTimer::ScopedTimer(const std::string& name) : name_(name) {}
|
|
|
|
ScopedTimer::~ScopedTimer() { print(name_); }
|
|
|
|
std::string getHostName(int maxlen, const char delim) {
|
|
std::string hostname(maxlen + 1, '\0');
|
|
if (gethostname(const_cast<char*>(hostname.data()), maxlen) != 0) {
|
|
ERROR("gethostname failed\n");
|
|
return nullptr;
|
|
}
|
|
int i = 0;
|
|
while ((hostname[i] != delim) && (hostname[i] != '\0') &&
|
|
(i < maxlen - 1)) i++;
|
|
hostname[i] = '\0';
|
|
return hostname.substr(0, i);
|
|
}
|
|
|
|
} // namespace rocshmem
|