-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
RFC: Add a method of randbool() that accepts an RNG as input #6014
Conversation
@@ -334,19 +334,23 @@ bitpack{T,N}(A::AbstractArray{T,N}) = convert(BitArray{N}, A) | |||
|
|||
## Random ## | |||
|
|||
function bitarray_rand_fill!(B::BitArray) | |||
function bitarray_rand_fill!(B::BitArray, random_function::Function) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently this is going to be slow, but it also seems odd to suddenly change from passing an AbstractRNG
to passing a function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I was trying to avoid code duplication (i can just copy the whole method). Is there a better way to avoid this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay yea, it does seem to be 10x slower:
root# julia speed_test.jl 10
elapsed time: 0.007485235 seconds (139956 bytes allocated)
elapsed time: 0.009702895 seconds (279740 bytes allocated)
elapsed time: 0.000283116 seconds (0 bytes allocated)
elapsed time: 0.001188023 seconds (160000 bytes allocated)
root# vi speed_test.jl
root# julia speed_test.jl 10000
elapsed time: 0.022272985 seconds (139956 bytes allocated)
elapsed time: 0.128069668 seconds (25557260 bytes allocated)
elapsed time: 0.015917311 seconds (0 bytes allocated)
elapsed time: 0.113222569 seconds (25437328 bytes allocated)
root# cat speed_test.jl
N = ARGS[1]
a = BitArray(int64(N))
@time for i in 1:10000
Base.bitarray_rand_fill!(a, true) # the original function
end
@time for i in 1:10000
Base.bitarray_rand_fill!(a, rand) # with passed in random function
end
@time for i in 1:10000
Base.bitarray_rand_fill!(a, true) # the original function
end
@time for i in 1:10000
Base.bitarray_rand_fill!(a, rand) # with passed in random function
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the bytes allocated is curious, why is this happening? @carlobaldassi
@JeffBezanson updated to be faster |
This is becoming kind of a tangled mess of definitions.
are too specific; it looks like they'd apply to any I'm not sure about
Whatever |
Okay I've cleaned up the definitions to be as general as they can be. I also modified the definition of bitarray_rand_fill to avoid the DefaultGlobalRNG, and avoid code duplication. I'm not sure that using "nothing" is a good idea. |
Well, sooner or later we're going to have to decide how the default RNG is actually specified. We can't put a branch everywhere to call either For example |
Unless I'm missing something, you can't just do "const DefaultRNG = MersenneTwister(...)" because we call directly into C code a lot, which wouldn't be able to use this constant anyway. I'm not sure how best to switch on this, so I put this flag in. Yes, Stefan said it makes sense for them all to take RNGs. |
The C code doesn't need to use the constant. One can write
|
I guess the only problem is if that has some overhead. If it is too much slower than the |
We can do that (I'm sure you mean |
Yea |
I'm not crazy about it either, but I'm not sure about the fastest way to do this dispatching with C and julia mixed in (I don't know Julia or C as well as you guys). It seems like the branching everywhere is unavoidable if we want these fast |
I was trying to get a discussion about how to do DefaultRNG going with this WIP: #6110 . I understand that MersenneTwister is an object with a seed state, but since you won't be passing it to methods anyway, you may want to avoid the duplication of the seed state since it could just go out of sync with the global RANDOM_SEED and seed in the |
Yea, I'm looking at adding an RNG to sprand() too, and to avoid duplication the best thing to do is either this weird use_default_rng=true with a keyword arg, or the DefaultGlobalRNG in order to avoid duplication. I think DefaultGlobalRNG will make it easier for all users of rand() in core and in user libraries. |
Do you have any sense of how much faster the |
@@ -333,16 +333,21 @@ bitpack{T,N}(A::AbstractArray{T,N}) = convert(BitArray{N}, A) | |||
|
|||
## Random ## | |||
|
|||
function bitarray_rand_fill!(B::BitArray) | |||
function bitarray_rand_fill!(B::BitArray, use_default_rng::Bool=true; rng=nothing) | |||
if length(B) == 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, Julia does not specialize on keyword arguments, and therefore the actual type of rng
is unknown when the compiler generates the code, thus resulting in big performance penalty.
Random number generating functions lie at the heart of many performance-critical applications, and therefore we should be very cautious about performance issues, and should ensure that no performance penalty is caused by failure of type inference.
I am wondering why you have to put rng
as keyword argument. I think you can simply do
function bitarray_rand_fill!(B::BitArray, rng::AbstractRNG)
...
end
bitarray_rand_fill!(B::BitArray) = bitarray_rand_fill!(B, default_rng)
In this way, the type of each argument is known at compile time, and as a consequence, we get much more performant codes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, that's the most straightforward way, but see above for discussions about the problems with default_rng.
Also, we'll have to move AbstractRNG over to another file, since it can't be used in bitarray.jl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still don't see the reason why this doesn't work.
Even if it is really the case, then I would say it is still worth duplicating codes to avoid performance penalty in such a basic function that is going to be used in performance-critical codes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I think we should first decide how to specify default rng. This would everything much simpler. To test whether use_default_rng
in a tight inner loop is performance killer and not a very elegant solution.
i saw perf tests in the code that mention |
Okay, it's just used in the micro benchmarks. I'll make a perf test and put it into test/perf. |
@JeffBezanson about 50% slower
|
How does this stand now? Would be nice to get it merged. |
6c7c7e3
to
1a4c02f
Compare
Recent RNG changes by @rfourquet have implemented this:
|
No description provided.