Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions projects/rccl/test/host/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ function(rccl_define_micro_source_lists)
ras-peers-test.cc # src/ras/peers.cc
ras-diagnostics-env-test.cc # src/ras/diagnostics_env.cc
ras-param-test.cc # src/ras/ras_param.cc
net-telemetry-test.cc # src/transport/net_telemetry.cc, src/include/net_telemetry.h
Comment thread
dhanavikram marked this conversation as resolved.
Resolved
tuning-test.cc # src/tuning/tuning.cc
tuning-general-test.cc
csv-tuner-test.cc # src/plugin/tuner/csv_tuner.cc
Expand Down Expand Up @@ -1520,6 +1521,7 @@ rccl_add_micro_binary(rccl-UnitTestsMicro
RAS_DIAGNOSTICS_ENV_CC_PATH="${RCCL_HOST_HIPIFY_DIR}/src/ras/diagnostics_env.cc"
RAS_PARAM_CC_PATH="${RCCL_HOST_HIPIFY_DIR}/src/ras/ras_param.cc"
COMM_DUMP_CC_PATH="${RCCL_HOST_HIPIFY_DIR}/src/commDump.cc"
NET_TELEMETRY_CC_PATH="${RCCL_HOST_HIPIFY_DIR}/src/transport/net_telemetry.cc"
# graph/tuning.cc keeps the basename, so add_file_unique() renames this one.
TUNING_CC_PATH="${RCCL_HOST_HIPIFY_DIR}/src/tuning/tuning_tmp.cc"
TUNING_GENERAL_CC_PATH="${RCCL_HOST_HIPIFY_DIR}/src/tuning/tuning_general.cc"
Expand Down
5 changes: 4 additions & 1 deletion projects/rccl/test/host/MICROTEST_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ export colliding non-`static` symbols; otherwise a unit needs its own binary:
`rasTimeoutFactorNs`, and `rasTimeoutFactorSec` symbols so it can link beside
`fakes/ras_param_fakes.cc` and the `ras-test.cc` timeout fake in the shared
microtest binary.
- `transport/net_telemetry.cc` and `include/net_telemetry.h`
(`NET_TELEMETRY_CC_PATH`, from `net-telemetry-test.cc`); suites
`NetTelemetry*Microtest.*`.
- `tuning/tuning_general.cc` (`TUNING_GENERAL_CC_PATH`, from
`tuning-general-test.cc`); suite `TuningGeneralMicrotest.*`. Covers the
shared step-count, hardware-index, time-estimation, thread-threshold,
Expand Down Expand Up @@ -741,7 +744,7 @@ symbol.
| `src/transport/p2p.cc` shareable-buffer entry points (`rccl-UnitTestsMicroDiagnostics`) | `fakes/transport_p2p_fakes.cc` |
| `src/transport/*`, `src/plugin/net.cc` | `fakes/transport_stubs.cc` |
| libc (`gethostname`, `dladdr`), process-wide for units linking libc directly | `fakes/libc_interposers.cc` |
| libc macro-renamed in one unit via `fakes/libc_seam.h` (sockets/stdio/exit for `ras/client.cc` and `ras/client_support.cc`; `gethostname`/`access` for `diagnostics/ib_write_bw.cc`; heap for `graph/rccl_graph_gen.cc`) | `fakes/libc_fakes.cc` |
| libc macro-renamed in one unit via `fakes/libc_seam.h` (sockets/stdio/exit for `ras/client.cc` and `ras/client_support.cc`; `gethostname`/`access` for `diagnostics/ib_write_bw.cc`; heap for `graph/rccl_graph_gen.cc`; files, `ioctl`, `atexit`, clock, aligned allocation, thread start and sleep for `transport/net_telemetry.cc`) | `fakes/libc_fakes.cc` |
| reusable RAS poll-entry, message, and diagnostics-context seams | `fakes/ras_fakes.cc` |
| core/lifecycle floor + data symbols | `fakes/nccl_stubs.cc` |
| reusable `nccl*` seams | `fakes/nccl_fakes.cc` |
Expand Down
104 changes: 103 additions & 1 deletion projects/rccl/test/host/fakes/libc_fakes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#include "fakes/libc_fakes.h"

// Puts the seam's 26 micro_* prototypes in scope so the compiler checks them against the definitions at the bottom of
// Puts the seam's micro_* prototypes in scope so the compiler checks them against the definitions at the bottom of
// this file. Without it the two lists are hand-maintained and both extern "C", so a drifted parameter type would link
// cleanly and corrupt arguments at run time. Include the undef half immediately: this file's defaults call real libc.
#include "fakes/libc_seam.h"
Comment thread
dhanavikram marked this conversation as resolved.
Resolved
Expand Down Expand Up @@ -36,6 +36,7 @@ std::vector<MicroFwriteCall> g_fwriteCalls;
std::vector<MicroPerrorCall> g_perrorCalls;
std::vector<int> g_closedFds;
std::vector<void*> g_freedPointers;
std::vector<void (*)(void)> g_atexitFns;
std::vector<FILE*> g_fprintfCalls;
std::vector<int> g_writtenFds;
std::vector<int> g_readFds;
Expand Down Expand Up @@ -284,6 +285,52 @@ static void DefaultFree(void* ptr) {
std::free(ptr);
}

// Fails rather than forwarding: the default read and close are fakes, and real files would make results
// host-dependent.
static int DefaultOpen(const char*, int, mode_t) {
Comment thread
dhanavikram marked this conversation as resolved.
Resolved
errno = ENOENT;
return -1;
}

// The filesystem and ioctl defaults below fail too, so a unit never sees the host.
static FILE* DefaultFopen(const char*, const char*) {
errno = ENOENT;
return nullptr;
}

static DIR* DefaultOpendir(const char*) {
errno = ENOENT;
return nullptr;
}

// Only reached with a DIR* a test hook handed out, so forward to real libc.
static struct dirent* DefaultReaddir(DIR* dir) { return ::readdir(dir); }
static int DefaultClosedir(DIR* dir) { return ::closedir(dir); }

static ssize_t DefaultReadlink(const char*, char*, size_t) {
errno = ENOENT;
return -1;
}

static int DefaultIoctl(int, unsigned long, void*) {
errno = ENOTTY;
return -1;
}

static int DefaultAtexit(void (*fn)(void)) {
g_atexitFns.push_back(fn);
return 0;
}

static int DefaultClockGettime(clockid_t clk, struct timespec* ts) { return ::clock_gettime(clk, ts); }
static int DefaultPosixMemalign(void** ptr, size_t alignment, size_t size) {
return ::posix_memalign(ptr, alignment, size);
}
static int DefaultPthreadCreate(pthread_t* thread, const pthread_attr_t* attr, void* (*fn)(void*), void* arg) {
return ::pthread_create(thread, attr, fn, arg);
}
static int DefaultNanosleep(const struct timespec* req, struct timespec* rem) { return ::nanosleep(req, rem); }

// ---------------------------------------------------------------------------

std::function<ssize_t(int, const void*, size_t)> g_write = DefaultWrite;
Expand All @@ -310,9 +357,22 @@ std::function<void(const char*)> g_perror = DefaultPerror;
std::function<void(int)> g_exit = DefaultExit;
std::function<int(char*, size_t)> g_gethostname = DefaultGethostname;
std::function<int(const char*, int)> g_access = DefaultAccess;
std::function<int(const char*, int, mode_t)> g_open = DefaultOpen;
std::function<void*(size_t)> g_malloc = DefaultMalloc;
std::function<void*(size_t, size_t)> g_calloc = DefaultCalloc;
std::function<void(void*)> g_free = DefaultFree;
std::function<FILE*(const char*, const char*)> g_fopen = DefaultFopen;
std::function<DIR*(const char*)> g_opendir = DefaultOpendir;
std::function<struct dirent*(DIR*)> g_readdir = DefaultReaddir;
std::function<int(DIR*)> g_closedir = DefaultClosedir;
std::function<ssize_t(const char*, char*, size_t)> g_readlink = DefaultReadlink;
std::function<int(int, unsigned long, void*)> g_ioctl = DefaultIoctl;
std::function<int(void (*)(void))> g_atexit = DefaultAtexit;
std::function<int(clockid_t, struct timespec*)> g_clockGettime = DefaultClockGettime;
std::function<int(void**, size_t, size_t)> g_posixMemalign = DefaultPosixMemalign;
std::function<int(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)> g_pthreadCreate =
DefaultPthreadCreate;
std::function<int(const struct timespec*, struct timespec*)> g_nanosleep = DefaultNanosleep;

ASSERT_HOOK_MATCHES_PROD(g_accept, ::accept);
ASSERT_HOOK_MATCHES_PROD(g_recv, ::recv);
Expand Down Expand Up @@ -361,16 +421,29 @@ void ResetLibcFakes() {
g_exit = DefaultExit;
g_gethostname = DefaultGethostname;
g_access = DefaultAccess;
g_open = DefaultOpen;
g_malloc = DefaultMalloc;
g_calloc = DefaultCalloc;
g_free = DefaultFree;
g_fopen = DefaultFopen;
g_opendir = DefaultOpendir;
g_readdir = DefaultReaddir;
g_closedir = DefaultClosedir;
g_readlink = DefaultReadlink;
g_ioctl = DefaultIoctl;
g_atexit = DefaultAtexit;
g_clockGettime = DefaultClockGettime;
g_posixMemalign = DefaultPosixMemalign;
g_pthreadCreate = DefaultPthreadCreate;
g_nanosleep = DefaultNanosleep;

g_writtenData.clear();
g_stdoutData.clear();
g_fwriteCalls.clear();
g_perrorCalls.clear();
g_closedFds.clear();
g_freedPointers.clear();
g_atexitFns.clear();
g_fprintfCalls.clear();
g_writtenFds.clear();
g_readFds.clear();
Expand Down Expand Up @@ -456,9 +529,38 @@ int micro_fflush(FILE* stream) { return g_fflush(stream); }
void micro_perror(const char* prefix) { g_perror(prefix); }
int micro_gethostname(char* name, size_t len) { return g_gethostname(name, len); }
int micro_access(const char* path, int mode) { return g_access(path, mode); }
int micro_open(const char* path, int flags, ...) {
mode_t mode = 0;
if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) {
va_list args;
va_start(args, flags);
mode = va_arg(args, mode_t);
va_end(args);
}
return g_open(path, flags, mode);
}
void* micro_malloc(size_t size) { return g_malloc(size); }
void* micro_calloc(size_t nmemb, size_t size) { return g_calloc(nmemb, size); }
void micro_free(void* ptr) { g_free(ptr); }
FILE* micro_fopen(const char* path, const char* mode) { return g_fopen(path, mode); }
DIR* micro_opendir(const char* path) { return g_opendir(path); }
struct dirent* micro_readdir(DIR* dir) { return g_readdir(dir); }
int micro_closedir(DIR* dir) { return g_closedir(dir); }
ssize_t micro_readlink(const char* path, char* buf, size_t len) { return g_readlink(path, buf, len); }
int micro_ioctl(int fd, unsigned long request, ...) {
va_list args;
va_start(args, request);
void* arg = va_arg(args, void*);
va_end(args);
return g_ioctl(fd, request, arg);
}
int micro_atexit(void (*fn)(void)) { return g_atexit(fn); }
int micro_clock_gettime(clockid_t clk, struct timespec* ts) { return g_clockGettime(clk, ts); }
int micro_posix_memalign(void** ptr, size_t alignment, size_t size) { return g_posixMemalign(ptr, alignment, size); }
int micro_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*fn)(void*), void* arg) {
return g_pthreadCreate(thread, attr, fn, arg);
}
int micro_nanosleep(const struct timespec* req, struct timespec* rem) { return g_nanosleep(req, rem); }

// Always forwards to the real vfprintf so stderr output still happens; records only the FILE* and never the
// formatted text, since no test needs the diagnostic's wording, only whether and where one was printed.
Expand Down
18 changes: 17 additions & 1 deletion projects/rccl/test/host/fakes/libc_fakes.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
// default and a reset, never as a hardcoded always-succeed. poll remains
// deliberately absent until a caller needs a shared recording surface.

#include <dirent.h>
#include <netdb.h>
#include <sys/socket.h>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#include <sys/types.h>

#include <cstddef>
Expand Down Expand Up @@ -82,7 +85,7 @@ struct MicroReadStep {
ssize_t DeliverReadStep(const MicroReadStep& step, void* buf, size_t count);

// ---------------------------------------------------------------------------
// Seams. Each defaults to the success behaviour described in the .cc.
// Seams. Each default is defined in the .cc.
// ---------------------------------------------------------------------------
extern std::function<ssize_t(int, const void*, size_t)> g_write;
extern std::function<ssize_t(int, void*, size_t)> g_read;
Expand All @@ -106,12 +109,24 @@ extern std::function<void(const char*)> g_perror;
extern std::function<void(int)> g_exit;
extern std::function<int(char*, size_t)> g_gethostname;
extern std::function<int(const char*, int)> g_access;
extern std::function<int(const char*, int, mode_t)> g_open;

// Fail an allocation for one case with a hook returning nullptr; g_freedPointers
// then shows whether the unit released what it had already taken on the way out.
extern std::function<void*(size_t)> g_malloc;
extern std::function<void*(size_t, size_t)> g_calloc;
extern std::function<void(void*)> g_free;
extern std::function<FILE*(const char*, const char*)> g_fopen;
extern std::function<DIR*(const char*)> g_opendir;
extern std::function<struct dirent*(DIR*)> g_readdir;
extern std::function<int(DIR*)> g_closedir;
extern std::function<ssize_t(const char*, char*, size_t)> g_readlink;
extern std::function<int(int, unsigned long, void*)> g_ioctl;
extern std::function<int(void (*)(void))> g_atexit;
extern std::function<int(clockid_t, struct timespec*)> g_clockGettime;
extern std::function<int(void**, size_t, size_t)> g_posixMemalign;
extern std::function<int(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)> g_pthreadCreate;
extern std::function<int(const struct timespec*, struct timespec*)> g_nanosleep;

// ---------------------------------------------------------------------------
// Observation points fed by the default seams. A test that installs its own
Expand All @@ -124,6 +139,7 @@ extern std::vector<MicroPerrorCall> g_perrorCalls; // every perror(), in order;
extern std::vector<int> g_closedFds; // fds passed to close(), in order
// Pointers passed to free(), in order, nullptrs included.
extern std::vector<void*> g_freedPointers;
extern std::vector<void (*)(void)> g_atexitFns; // handlers the default atexit recorded instead of registering
// FILE* argument of every fprintf() the unit made, in order. Never the formatted text: fprintf always forwards to
// the real vfprintf, so this only proves whether and where a diagnostic was printed, not what it said.
extern std::vector<FILE*> g_fprintfCalls;
Expand Down
28 changes: 28 additions & 0 deletions projects/rccl/test/host/fakes/libc_seam.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@

// The headers that declare the names renamed below, so this file satisfies its own ordering rule and a unit following
// the recipe above cannot get it wrong by forgetting one. Include guards make the includer's own copies free.
#include <dirent.h>
#include <pthread.h>
#include <time.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
Expand Down Expand Up @@ -72,6 +76,18 @@ void micro_free(void*);
int micro_fprintf(FILE*, const char*, ...) __attribute__((format(printf, 2, 3)));
int micro_gethostname(char*, size_t);
int micro_access(const char*, int);
int micro_open(const char*, int, ...);
FILE* micro_fopen(const char*, const char*);
DIR* micro_opendir(const char*);
struct dirent* micro_readdir(DIR*);
int micro_closedir(DIR*);
ssize_t micro_readlink(const char*, char*, size_t);
int micro_ioctl(int, unsigned long, ...);
int micro_atexit(void (*)(void));
int micro_clock_gettime(clockid_t, struct timespec*);
int micro_posix_memalign(void**, size_t, size_t);
int micro_pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*);
int micro_nanosleep(const struct timespec*, struct timespec*);
} // extern "C"

#define write micro_write
Expand Down Expand Up @@ -100,3 +116,15 @@ int micro_access(const char*, int);
#define fprintf micro_fprintf
#define gethostname micro_gethostname
#define access micro_access
#define open micro_open
#define fopen micro_fopen
Comment thread
dhanavikram marked this conversation as resolved.
Resolved
#define opendir micro_opendir
Comment thread
dhanavikram marked this conversation as resolved.
Resolved
#define readdir micro_readdir
#define closedir micro_closedir
#define readlink micro_readlink
#define ioctl micro_ioctl
#define atexit micro_atexit
#define clock_gettime micro_clock_gettime
#define posix_memalign micro_posix_memalign
#define pthread_create micro_pthread_create
#define nanosleep micro_nanosleep
12 changes: 12 additions & 0 deletions projects/rccl/test/host/fakes/libc_seam_undef.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@
// real libc again; a test that wants a seamed call can name micro_* directly.
// No include guard on purpose: the push/pop pair is positional.

#undef nanosleep
#undef pthread_create
#undef posix_memalign
#undef clock_gettime
#undef atexit
#undef ioctl
#undef readlink
#undef closedir
#undef readdir
#undef opendir
#undef fopen
#undef open
#undef access
#undef gethostname
#undef free
Expand Down
2 changes: 2 additions & 0 deletions projects/rccl/test/host/net-ib-cast-scheduler-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ class NetIbCastSchedulerLogMicrotest : public NetIbCastSchedulerMicrotest {
std::string LogFile() const { return dir_ + "/cast_log_nodeA_" + std::to_string(getpid()); }

std::string dir_;
// The libc_fakes fopen default fails; these tests write a real file under dir_.
ScopedHook<FILE*(const char*, const char*)> fopen_{g_fopen, ::fopen};
ScopedHook<int(char*, size_t)> hostname_{g_gethostname, [](char* name, size_t len) {
snprintf(name, len, "nodeA");
return 0;
Expand Down
Loading
Loading