Search code examples
pythonnumpyruntimegpucupy

Cupy is slower than numpy


I tried to speed up my python code with cupy instead of numpy. The problem here is, that using cupy, my code got drastically slower. Maybe I went a little bit to naive on that problem.

Maybe anyone can find a bottleneck in my code:

import cupy as np
import time as ti

def f(y, t):
    y_ = np.zeros(2 * N_1*N_2) # n: e-6, c: e-5
    for i in range(0, N_1*N_2):
        y_[i] = y[i + N_1*N_2] # n: e-7, c: e-5 or e-6
    for i in range(N_1*N_2):
        sum = -4*y[i] # n: e-7, c: e-7 after some statements e-5
        if (i + 1 in indexes) and (not (i in indi)):
            sum += y[i+1] # n: e-7, c: e-7 after some statements e-5
        if (i - 1) in indexes and (i % N_1 != 0):
            sum += y[i-1] # n: e-7, c: e-7 after some statements e-5
        if i + N_1 in indexes:
            sum += y[i+N_1] # n: e-7, c: e-7 after some statements e-5
        if i - N_1 in indexes:
            sum += y[i-N_1] # n: e-7, c: e-7 after some statements e-5
        y_[i + N_1*N_2] = sum

    return y_

def k_1(y, t, h):
    return np.asarray(f(y, t)) * h

def k_2(y, t, h):
    return np.asarray(f(np.add(np.asarray(y) , np.multiply(1/2 , k_1(y, t, h))), t + 1/2 * h)) * h

# k_2, k_4 look just like k_2, may be with an 1/2 here or there

# some init stuff is happening here

while t < T_end:
    # also some magic happening here which is just data saving
    y = np.asarray(y) + 1/6*(k_1(y, t, m) + 2*k_2(y, t, m) + 2*k_3(y, t, m) + k_4(y, t, m))
    t += m

EDIT I tried to benchmark my code and here are some results they can be seen as a comment in the code. Each number stays for one line. The units are seconds. n: Numpy, c:CuPy, i mostly give a rough estimate of the order. Additional i tested

np.multiply # n: e-6, c: e-5

and

np.add # n: e-5 or e-6, c: 0.005 or e-5

Solution

  • Your code is not slow because numpy is slow but because you call many (python) functions, and calling functions (and iterating and accessing objects and basically everything in python) is slow in python. Thus cupy will not help you (but probably harm performance because it has to do more setup e.g. copying data over to the gpu). If you can formulate your algorithm to use less python functions (vectorizing as in the other answer) this will speedup your code tremendously (you probably do not need cupy).

    You could also look into numba which compiles your code with llvm in native code. If you do so be sure to read some documenation and use nopython=True, otherwise you will only switch slow cupy code with slow numba code.