Loading...
Searching...
No Matches
launcher.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * How many tasks the job launcher started this process as, read from the
5 * environment rather than from MPI.
6 *
7 * The GPU binaries link no MPI -- the published -cuda image has none at all --
8 * so they cannot ask MPI_Comm_size how many of them are running. They can ask
9 * the launcher, which says so in the environment: srun sets
10 * SLURM_STEP_NUM_TASKS for the step it starts, and the MPI launchers set a
11 * size variable of their own. That is enough to tell one task from four, which
12 * is all a binary with no multi-process mode needs to know.
13 *
14 * SLURM_NTASKS is deliberately not consulted. `salloc -n 4` exports it to the
15 * interactive shell, where a program run directly is still one process, and
16 * refusing there would be wrong. SLURM_STEP_NUM_TASKS exists only inside a step
17 * srun actually launched.
18 */
19
20#include <cstdlib>
21#include <functional>
22#include <string>
23
24namespace q3 {
25namespace cli {
26
27/// What the launcher said, and which variable said it.
29 /// Tasks in this job step; 1 when no launcher variable was found.
30 int count = 1;
31 /// The variable the count came from, empty when the count is the default.
32 std::string variable;
33};
34
35/// Environment reader, so the detection can be tested without setenv.
36using EnvironmentLookup = std::function<const char*(const char*)>;
37
38/**
39 * Read the task count from `lookup`, taking the largest value any launcher
40 * variable reports and remembering which one it was -- a message that names the
41 * variable can be checked by the reader, and a wrong guess can be argued with.
42 */
44 static constexpr const char* task_count_variables[] = {
45 "SLURM_STEP_NUM_TASKS", // srun, for the step rather than the allocation
46 "PMI_SIZE", // MPICH and Cray MPICH, including under srun
47 "OMPI_COMM_WORLD_SIZE", // Open MPI's mpirun
48 "MV2_COMM_WORLD_SIZE", // MVAPICH2
49 };
50
51 LauncherTasks tasks;
52 for (const char* variable : task_count_variables) {
53 const char* value = lookup(variable);
54 if (value == nullptr || *value == '\0') {
55 continue;
56 }
57 int reported = 0;
58 try {
59 reported = std::stoi(value);
60 } catch (const std::exception&) {
61 continue; // a variable that does not hold a number says nothing
62 }
63 if (reported > tasks.count) {
64 tasks.count = reported;
65 tasks.variable = variable;
66 }
67 }
68 return tasks;
69}
70
71/// The same, against the real environment.
73 return detect_launcher_tasks([](const char* variable) { return std::getenv(variable); });
74}
75
76} // namespace cli
77} // namespace q3
std::function< const char *(const char *)> EnvironmentLookup
Environment reader, so the detection can be tested without setenv.
Definition launcher.hpp:36
LauncherTasks detect_launcher_tasks()
The same, against the real environment.
Definition launcher.hpp:72
What the launcher said, and which variable said it.
Definition launcher.hpp:28
int count
Tasks in this job step; 1 when no launcher variable was found.
Definition launcher.hpp:30
std::string variable
The variable the count came from, empty when the count is the default.
Definition launcher.hpp:32