Skip to content

Commit 46e722b

Browse files
committed
Initial commit
0 parents  commit 46e722b

File tree

2 files changed

+300
-0
lines changed

2 files changed

+300
-0
lines changed

README.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
## Slurm SPANK GPU Compute Mode plugin
2+
3+
The GPU Compute mode [SPANK](https://slurm.schedmd.com/spank.html) plugin for
4+
[Slurm](https://slurm.schedmd.com/) allows users to choose the compute mode of
5+
GPUs they submit jobs to.
6+
7+
### Rationale
8+
9+
NVIDIA GPUs can be set to operate under different compute modes:
10+
11+
* `Default` (shared): Multiple host threads can use the device
12+
at the same time.
13+
* `Exclusive-process`: Only one CUDA context may be created on
14+
the device across all processes in the system.
15+
* `Prohibited`: No CUDA context can be created on the device.
16+
17+
_More information is available in the [CUDA Programming
18+
guide](http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#compute-modes)_
19+
20+
21+
To ensure optimal performance, process isolation and avoid situations where
22+
multiple processes unintentionally run on the same GPU, it's often recommended
23+
to set the GPU compute mode to `Exclusive-process`.
24+
25+
Unfortunately, some legacy applications may require to run concurrent processes
26+
on a single GPU, to function properly, and thus need the GPUs to be set in the
27+
`Default` (_i.e._ shared) compute mode.
28+
29+
Hence the need for a mechanism that would allow users to choose the compute
30+
mode of the GPUs their job will run on.
31+
32+
33+
## Installation
34+
35+
**Requirements**:
36+
* [`slurm-spank-lua`](https://github.com/stanford-rc/slurm-spank-lua)
37+
(submission and execution nodes)
38+
* [`nvidia-smi`](https://developer.nvidia.com/nvidia-system-management-interface)
39+
(execution nodes)
40+
41+
The Slurm SPANK GPU Compute Mode plugin is written in [Lua](http://www.lua.org)
42+
and require the
43+
[`slurm-spank-lua`](https://github.com/stanford-rc/slurm-spank-lua) plugin to
44+
work.
45+
46+
47+
Once the `slurm-spank-lua` plugin is installed and configured, the
48+
`gpu_cmode.lua` script can be dropped in the appropriate directory (by default,
49+
`/etc/slurm/lua.d`, or any other location specified in the `plugstack.conf`
50+
configuration file).
51+
52+
53+
Note that both the Slurm SPANK Lua plugin and the GPU Compute mode Lua plugin
54+
will need to be present on both the submission host(s) (where
55+
`srun`/`sbatch` commands are executed) and the execution host(s) (where the job
56+
actually runs).
57+
58+
59+
_Note_: The plugin defines a default GPU compute mode (`exclusive`), which is
60+
used to re-set the GPUs at the end of a job. The default mode can be changed
61+
by editing the value of `default_cmode` in the script.
62+
63+
64+
65+
## Usage
66+
67+
The Slurm SPANK GPU Compute Mode plugin introduces a new option to `srun` and
68+
`sbatch`: `--gpu_cmode`.
69+
70+
```
71+
$ srun --help
72+
[...]
73+
--gpu_cmode=<shared|exclusive|prohibited>
74+
Set the GPU compute mode on the allocated GPUs to
75+
shared, exclusive or prohibited. Default is
76+
exclusive
77+
[...]
78+
```
79+
80+
### Examples
81+
82+
##### Requesting `Default` compute mode
83+
> `--gpu_cmode=shared`
84+
85+
```
86+
$ srun --gres gpu:1 --gpu_cmode=shared "nvidia-smi --query-gpu=compute_mode --format=csv,noheader"
87+
Default
88+
```
89+
90+
##### Requesting `Exclusive-process` compute mode
91+
> `--gpu_cmode=exclusive`
92+
93+
```
94+
$ srun --gres gpu:1 --gpu_cmode=exclusive "nvidia-smi --query-gpu=compute_mode --format=csv,noheader"
95+
Exclusive_Process
96+
```
97+
98+
##### Requesting `prohibited` compute mode
99+
> `--gpu_cmode=prohibited`
100+
101+
```
102+
$ srun --gres gpu:1 --gpu_cmode=prohibited "nvidia-smi --query-gpu=compute_mode --format=csv,noheader"
103+
Prohibited
104+
```
105+
106+
##### Multi-GPU job
107+
108+
```
109+
$ srun --gres gpu:4 --gpu_cmode=shared "nvidia-smi --query-gpu=compute_mode --format=csv,noheader"
110+
Default
111+
Default
112+
Default
113+
Default
114+
```
115+
116+
##### Multi-node job
117+
118+
```
119+
$ srun -l -N 2 --ntasks-per-node=1 --gres gpu:1 --gpu_cmode=shared "nvidia-smi --query-gpu=compute_mode --format=csv,noheader"
120+
1: Default
121+
0: Default
122+
```
123+
124+
**NB**: If the `--gpu_cmode` option is not used, no modification will be made
125+
to the current compute mode of the GPUs, and the site default will be used.
126+

gpu_cmode.lua

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
-- ============================================================================
2+
-- SPANK plugin to allow users to choose the compute mode on the GPUs allocated
3+
-- to their job. Requires `nvidia-smi` on the compute node, and the Slurm SPANK
4+
-- Lua plugin.
5+
--
6+
-- Adds a --gpu_cmode=MODE option to srun/sbatch/salloc, with MODE:
7+
-- 0: shared
8+
-- 1: exclusive (exclusive_thread: deprecated, use 3)
9+
-- 2: prohibited
10+
-- 3: exclusive (exclusive_process)
11+
--
12+
-- Reference:
13+
-- http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#compute-modes
14+
--
15+
-- # Author : Kilian Cavalotti <kilian@stanford.edu>
16+
-- # Created : 2018/01/22
17+
-- # License : GPL 2.0
18+
-- ============================================================================
19+
20+
21+
--
22+
-- constants ------------------------------------------------------------------
23+
--
24+
25+
-- plugin name (for logging)
26+
--
27+
myname = "SPANK:gpu_cmode"
28+
29+
-- GPU compute modes definitions
30+
--
31+
valid_cmodes = {
32+
[0]="shared",
33+
[1]="exclusive",
34+
[2]="prohibited"
35+
}
36+
-- reverse index
37+
--
38+
cmodes_index = {}
39+
for k,v in pairs(valid_cmodes) do cmodes_index[v]=k end
40+
41+
-- default mode
42+
-- GPUs will be reset to that mode at the end of the job
43+
--
44+
default_cmode = "exclusive"
45+
46+
47+
-- define new --gpu_cmode option for srun/salloc/sbatch
48+
--
49+
spank_options = {
50+
{
51+
name = "gpu_cmode",
52+
usage = "Set the GPU compute mode on the allocated GPUs to " ..
53+
"shared, exclusive or prohibited. Default is " ..
54+
default_cmode ,
55+
arginfo = "<shared|exclusive|prohibited>",
56+
has_arg = 1,
57+
cb = "opt_handler"
58+
},
59+
}
60+
61+
62+
--
63+
-- functions ------------------------------------------------------------------
64+
--
65+
66+
-- execute command and return output
67+
--
68+
function exec(cmd)
69+
local handle = io.popen (cmd)
70+
local result = handle:read("*a") or ""
71+
handle:close()
72+
result = string.gsub(result, "\n$", "")
73+
return result
74+
end
75+
76+
-- validate compute mode
77+
--
78+
function validate_cmode(cmode)
79+
for _, value in pairs(valid_cmodes) do
80+
if value == cmode then
81+
return true
82+
end
83+
end
84+
return false
85+
end
86+
87+
-- check options
88+
--
89+
function opt_handler(val, optarg, isremote)
90+
cmode = optarg
91+
if isremote or validate_cmode(optarg) then
92+
return SPANK.SUCCESS
93+
end
94+
return SPANK.FAILURE
95+
end
96+
97+
98+
--
99+
-- SPANK functions ------------------------------------------------------------
100+
-- cf. https://slurm.schedmd.com/spank.html
101+
--
102+
103+
-- SPANK function, called after privileges are temporarily dropped.
104+
-- needs to run as root, but in the job cgroup context, if any.
105+
--
106+
function slurm_spank_user_init(spank)
107+
108+
-- if context is not "remote" or compute mode is not defined, do nothing
109+
if spank.context ~= "remote" or cmode == nil then
110+
return SPANK.SUCCESS
111+
end
112+
113+
-- get GPU ids from CUDA_VISIBLE_DEVICES
114+
device_ids = spank:getenv("CUDA_VISIBLE_DEVICES")
115+
if device_ids == nil or device_ids == "" then
116+
SPANK.log_error(myname .. ": CUDA_VISIBLE_DEVICES not set.")
117+
return SPANK.FAILURE
118+
end
119+
120+
-- check for nvidia-smi
121+
nvs_path = exec("which nvidia-smi")
122+
if nvs_path:match("nvidia%-smi$") == nil then
123+
SPANK.log_error(myname .. ": can't find nvidia-smi in PATH.")
124+
return SPANK.FAILURE
125+
end
126+
127+
-- set compute mode on GPUs
128+
SPANK.log_info(myname .. ": changing compute mode to '%s' on GPU(s): %s\n",
129+
cmode, device_ids)
130+
local cmd = nvs_path .. " -c " .. cmodes_index[cmode] ..
131+
" -i " .. device_ids
132+
local ret = tonumber(os.execute(cmd))
133+
SPANK.log_debug(myname .. ": DEBUG: cmd = %s\n", cmd)
134+
SPANK.log_debug(myname .. ": DEBUG: ret = %s\n", ret)
135+
136+
-- check return code
137+
if ret ~= 0 then
138+
SPANK.log_error(myname .. ": error setting compute mode go to '%s'" ..
139+
" on GPU(s): %s\n", cmode, device_ids)
140+
return SPANK.FAILURE
141+
end
142+
143+
return SPANK.SUCCESS
144+
end
145+
146+
147+
-- SPANK function called for each task as its exit status is collected by Slurm
148+
-- needs to run as root, in the job cgroup context, if any.
149+
--
150+
function slurm_spank_task_exit(spank)
151+
152+
-- if context is not "remote" or compute mode is not defined, do nothin'
153+
if spank.context ~= "remote" or cmode == nil then
154+
return SPANK.SUCCESS
155+
end
156+
157+
-- reset compute mode on GPUs
158+
SPANK.log_info(myname .. ": resetting compute mode to default '%s'" ..
159+
" on GPU(s): %s\n", default_cmode, device_ids)
160+
local cmd = nvs_path .. " -c " .. cmodes_index[default_cmode] ..
161+
" -i " .. device_ids
162+
local ret = tonumber(os.execute(cmd))
163+
SPANK.log_debug(myname .. ": DEBUG: cmd = %s\n", cmd)
164+
SPANK.log_debug(myname .. ": DEBUG: ret = %s\n", ret)
165+
166+
-- check return
167+
if ret ~= 0 then
168+
SPANK.log_error(myname .. ": error resetting compute mode to default"..
169+
" '%s' on GPU(s): %s\n", default_cmode, device_ids)
170+
return SPANK.FAILURE
171+
end
172+
173+
return SPANK.SUCCESS
174+
end

0 commit comments

Comments
 (0)