Slow init of GPUs

kalo: <p>I know the init process takes more time on machines with more GPUs, but since we are calling the Pytorch script from external scripts it is kind of a bottleneck for our process.</p>
<p>See the basic example below:</p>
<blockquote>
<p>import torch</p>
<p>cuda0 = torch.device(‘cuda:0’)<br>
cuda1 = torch.device(‘cuda:1’)<br>
cuda2 = torch.device(‘cuda:2’)<br>
cuda3 = torch.device(‘cuda:3’)</p>
<p>x0 = torch.tensor([1], device=cuda0)<br>
x1 = torch.tensor([1], device=cuda1)<br>
x2 = torch.tensor([1], device=cuda2)<br>
x3 = torch.tensor([1], device=cuda3)</p>
</blockquote>
<p>So the example takes</p>
<ul>
<li>~24s on a machine with 8GPUs. Tested with 8x2080TI and 8xA6000.</li>
<li>~15s on machine with 4GPUs. Tested with 4xA6000.</li>
<li>~5s on machine with 2GPUs (in example above removed x2 and x3). Test on 2x3090.</li>
<li>~8s on machine with 8GPUs when init only one GPU (i.e. x1,x2,x3 are removed). Test on 8xA6000</li>
</ul>
<p>And since we call it again and again it becomes an issue.</p>
<p>My understanding is that it is that slow because the initialization process of the GPUs.</p>
<p>So I was wonder whether I can cache something so it is slow only the first time and then when we call the script again it is faster?</p>

ptrblck: <p>No, you won’t be able to cache anything as the CUDA context creation is taking some of the init time and is loading the driver, the native PyTorch kernels, the CUDA math lib kernels (cublas, cuDNN etc.) and needs time to load the actual data onto the device.<br>
In case you are using CUDA 11.7+, you can activate lazy module loading via <code>CUDA_MODULE_LOADING=LAZY</code> , which will avoid pre-loading every kernel and will load it lazily once it’s needed. This will speed up the init process but will add a small overhead for each new kernel as it has to be loaded into the CUDA context before its first execution.</p>

kalo: <p>Thanks. Tried the CUDA_MODULE_LOADING=LAZY on one of the machines which is with CUDA 11.7 but didn’t help.</p>
<p>I guess the PyTorch scripts will have to stay in memory and work like a server, get calls from outside instead of loading the scripts each time.</p>

ptrblck: <p>You would need to build PyTorch with CUDA 11.7 (or install the nightly binaries) to see the effect. Installing the CUDA toolkit 11.7 on your system with a PyTorch binary using another CUDA runtime (e.g. 11.6) will not work. You should also see a reduction in memory of the CUDA context size and could use it to double check if lazy loading is working.</p>
<p>I don’t fully understand the second point, so could you explain which scripts are supposed to stay in memory?</p>

kalo: <p>Thank you  for the suggestions.  It makes sense,  I will try it.</p>
<p>Currently we have a web server which loads PHP scripts and then they execute the python (PyTorch) scripts using a shell type interface. But this creates a bottleneck because each reload takes too much time. I.e. the actual work is done in 10s but load time is another 10s.</p>
<p>So it will be probably much more efficient to load the python and leave it in memory where it will take requests,  do the compute and return the results.</p>

ptrblck: <p>Ah yes, thanks for the explanation.<br>
You are right and I would also suggest to try to initialize the Python/PyTorch process once and reuse it later with new requests. I’m not sure which web server application you are using, but would it be possible to write a startup and teardown method which would keep the PyTorch process alive?</p>

kalo: <p>Yeah, that’s what I will have to do.</p>