Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with stochastic forcing implementation on GPU #350

Closed
mncrowe opened this issue Mar 8, 2024 · 14 comments · Fixed by #351
Closed

Issue with stochastic forcing implementation on GPU #350

mncrowe opened this issue Mar 8, 2024 · 14 comments · Fixed by #351
Labels
🐞 bug Something isn't working 🎮 gpu

Comments

@mncrowe
Copy link
Contributor

mncrowe commented Mar 8, 2024

Hi All,

I'm having an issue with running the singlelayerqg_betaforced.jl example with dev = GPU(). It seems to be that calcF! calls are failing though it's unclear to me what the issue is (error output below). Removing calcF=calcF! from the prob definition allows the script to run and the unforced example runs with no issues.

Is this some new bug introduced by an update to one of the packages or perhaps an issue with my installation?

Matt

out.log

@navidcy
Copy link
Member

navidcy commented Mar 9, 2024

thanks!

if you change

@. Fh = sqrt(forcing_spectrum) * cis(2π * random_uniform(T)) / sqrt(clock.dt)

to

Fh .= sqrt.(forcing_spectrum) .* cis.(2π * random_uniform(T, size(forcing_spectrum)...)) ./ sqrt(clock.dt)

it should work. However, it allocates an array and I'm trying to find a better way to do this and will open a PR.

@navidcy navidcy added 🐞 bug Something isn't working 🎮 gpu labels Mar 9, 2024
@glwagner
Copy link
Member

glwagner commented Mar 9, 2024

The problem is to generate random numbers without allocating data? Is rand! supported by CUDA?

@glwagner
Copy link
Member

glwagner commented Mar 9, 2024

I think it is:

help?> CUDA.rand!
  rand!([rng=default_rng()], A, [S=eltype(A)])

  Populate the array A with random values. If S is specified (S can be a type or a collection, cf. rand for details), the values are picked
  randomly from S. This is equivalent to copyto!(A, rand(rng, S, size(A))) but without allocating a new array.

  Examples
  ≡≡≡≡≡≡≡≡

  julia> rng = MersenneTwister(1234);

  julia> rand!(rng, zeros(5))
  5-element Vector{Float64}:
   0.5908446386657102
   0.7667970365022592
   0.5662374165061859
   0.4600853424625171
   0.7940257103317943

@glwagner
Copy link
Member

glwagner commented Mar 9, 2024

Not sure what distribution you're going for but basically you need to preallocate an array:

sz = size(forcing_spectrum)
ϵ = CuArray(rand(T, sz...))

# then later, within calcF!
rand!(ϵ)
@. Fh = sqrt(forcing_spectrum) * cis(2π * ϵ) / sqrt(clock.dt)

bit of a sketch but its something like that

@navidcy
Copy link
Member

navidcy commented Mar 9, 2024

Which version of CUDA you using? Because I don't get this for CUDA v5.2.

@glwagner
Copy link
Member

glwagner commented Mar 9, 2024

5.1.2

@navidcy
Copy link
Member

navidcy commented Mar 9, 2024

I found that Random.rand! will work both on Arrays and CuArrays provided you give

Random.rand!(Random.default_rng(), A)

or

Random.rand!(CUDA.default_rng(), A)

@glwagner
Copy link
Member

glwagner commented Mar 9, 2024

(BaroclinicAdjustments) pkg> add CUDA@5.2
   Resolving package versions...
  No Changes to `~/Projects/AwesomeOceananigans/BaroclinicAdjustments/Project.toml`
  No Changes to `~/Projects/AwesomeOceananigans/BaroclinicAdjustments/Manifest.toml`

(BaroclinicAdjustments) pkg> st
Status `~/Projects/AwesomeOceananigans/BaroclinicAdjustments/Project.toml`
  [052768ef] CUDA v5.2.0
  [e9467ef8] GLMakie v0.9.9
⌃ [9e8cae18] Oceananigans v0.90.9
  [de0858da] Printf
Info Packages marked with ⌃ have new versions available and may be upgradable.

julia> using CUDA

julia> CUDA.rand!
rand! (generic function with 90 methods)

help?> CUDA.rand!
  rand!([rng=default_rng()], A, [S=eltype(A)])

  Populate the array A with random values. If S is specified (S can be a type or a collection, cf. rand for details), the values are picked
  randomly from S. This is equivalent to copyto!(A, rand(rng, S, size(A))) but without allocating a new array.

  Examples
  ≡≡≡≡≡≡≡≡

  julia> rng = MersenneTwister(1234);

  julia> rand!(rng, zeros(5))
  5-element Vector{Float64}:
   0.5908446386657102
   0.7667970365022592
   0.5662374165061859
   0.4600853424625171
   0.7940257103317943

@glwagner
Copy link
Member

glwagner commented Mar 9, 2024

oh so it does work

@navidcy
Copy link
Member

navidcy commented Mar 9, 2024

OK, then that's the cleanest solution! rand! it is!

@navidcy
Copy link
Member

navidcy commented Mar 10, 2024

OK, for the record, the best solution is to change the calcF! and bit above to:

random_normal! = dev==CPU() ? Random.randn! :
                 dev==GPU() ? CUDA.randn! :
                 error("dev must be CPU() or GPU()")

function calcF!(Fh, sol, t, clock, vars, params, grid)
  random_normal!(Fh)
  @. Fh *= sqrt(forcing_spectrum) / sqrt(clock.dt)
end

@navidcy navidcy changed the title Issue with singlelayerqg_betaforced.jl example on GPU Issue with stochastic forcing implementation on GPU Mar 10, 2024
@glwagner
Copy link
Member

OK, for the record, the best solution is to change the calcF! and bit above to:

random_normal! = dev==CPU() ? Random.randn! :
                 dev==GPU() ? CUDA.randn! :
                 error("dev must be CPU() or GPU()")

function calcF!(Fh, sol, t, clock, vars, params, grid)
  random_normal!(Fh)
  @. Fh *= sqrt(forcing_spectrum) / sqrt(clock.dt)
end

Do you need the if-statement? Is it really true that randn! does not dispatch on array type?

@navidcy
Copy link
Member

navidcy commented Mar 10, 2024

Do you need the if-statement? Is it really true that randn! does not dispatch on array type?

You are correct!

julia> using CUDA, Random, BenchmarkTools

julia> A = CUDA.zeros(3, 4)
3×4 CuArray{Float32, 2, CUDA.Mem.DeviceBuffer}:
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0

julia> @btime CUDA.@sync Random.randn!($A);
  16.554 μs (10 allocations: 352 bytes)

julia> @btime CUDA.@sync CUDA.randn!($A);
  17.563 μs (10 allocations: 352 bytes)

@glwagner
Copy link
Member

Here's how you see it directly:

julia> Random.randn! === CUDA.randn!
true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐞 bug Something isn't working 🎮 gpu
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants