diff --git a/src/BaseBenchmarks.jl b/src/BaseBenchmarks.jl index 76ceb6dc..a30d4400 100644 --- a/src/BaseBenchmarks.jl +++ b/src/BaseBenchmarks.jl @@ -17,6 +17,7 @@ const MODULES = Dict("array" => :ArrayBenchmarks, "io" => :IOBenchmarks, "linalg" => :LinAlgBenchmarks, "micro" => :MicroBenchmarks, + "nullable" => :NullableBenchmarks, "parallel" => :ParallelBenchmarks, "problem" => :ProblemBenchmarks, "scalar" => :ScalarBenchmarks, diff --git a/src/nullable/NullableBenchmarks.jl b/src/nullable/NullableBenchmarks.jl new file mode 100644 index 00000000..12cd3c34 --- /dev/null +++ b/src/nullable/NullableBenchmarks.jl @@ -0,0 +1,131 @@ +module NullableBenchmarks + +include(joinpath(dirname(@__FILE__), "..", "utils", "RandUtils.jl")) + +using .RandUtils +using BenchmarkTools + +const SUITE = BenchmarkGroup() + +#################### +# basic operations # +#################### + +g = addgroup!(SUITE, "basic") + +for T in (Bool, Int8, Int64, Float32, Float64, BigInt, BigFloat) + x = Nullable(one(T)) + g["get1", string(x)] = @benchmarkable get($x) + + for x in (Nullable(one(T)), Nullable{T}()) + g["isnull", string(x)] = @benchmarkable isnull($x) + g["get2", string(x)] = @benchmarkable get($x, $(zero(T))) + + for y in (Nullable(one(T)), Nullable(zero(T)), Nullable{T}()) + g["isequal", string(x), string(y)] = @benchmarkable isequal($x, $y) + end + end +end + +#################### +# nullable array # +#################### + +g = addgroup!(SUITE, "nullablearray") + +immutable NullableArray{T, N} <: AbstractArray{Nullable{T}, N} + values::Array{T, N} + isnull::Array{Bool, N} +end + +@inline function Base.getindex{T, N}(X::NullableArray{T, N}, I::Int...) + if isbits(T) + Nullable{T}(X.values[I...], X.isnull[I...]) + else + if X.isnull[I...] + Nullable{T}() + else + Nullable{T}(X.values[I...]) + end + end +end + +Base.size(X::NullableArray) = size(X.values) + +const VEC_LENGTH = 1000 + +function perf_sum{T}(X::NullableArray{T}) + s = zero(typeof(zero(T)+zero(T))) + @inbounds for i in eachindex(X) + s += get(X[i], zero(T)) + end + s +end + +function perf_countnulls(X::NullableArray) + n = 0 + @inbounds for i in eachindex(X) + n += isnull(X[i]) + end + n +end + +function perf_countequals(X::NullableArray, Y::NullableArray) + s = 0 + @inbounds for i in eachindex(X, Y) + s += isequal(X[i], Y[i]) + end + s +end + +for T in (Bool, Int8, Int64, Float32, Float64, BigInt, BigFloat) + if T == BigInt + S = Int128 + elseif T == BigFloat + S = Float64 + else + S = T + end + + # 10% of missing values + X = NullableArray(Array{T}(samerand(S, VEC_LENGTH)), Array(samerand(VEC_LENGTH) .> .9)) + Y = NullableArray(Array{T}(samerand(S, VEC_LENGTH)), Array(samerand(VEC_LENGTH) .> .9)) + + g["perf_sum", string(T)] = @benchmarkable perf_sum($X) + g["perf_countnulls", string(T)] = @benchmarkable perf_countnulls($X) + g["perf_countequals", string(T)] = @benchmarkable perf_countequals($X, $Y) +end + + +function perf_all(X::NullableArray{Bool}) + @inbounds for i in eachindex(X) + x = X[i] + if isnull(x) + return Nullable{Bool}() + elseif get(x) + return Nullable(false) + end + end + Nullable(true) +end + +function perf_any(X::NullableArray{Bool}) + allnull = true + @inbounds for i in eachindex(X) + x = X[i] + if !isnull(x) + allnull = false + get(x) && return Nullable(true) + end + end + allnull ? Nullable{Bool}() : Nullable(false) +end + +# Ensure no short-circuit happens +X = NullableArray(fill(true, VEC_LENGTH), fill(false, VEC_LENGTH)) +# 10% of missing values +Y = NullableArray(fill(false, VEC_LENGTH), Array(samerand(VEC_LENGTH) .> .9)) +g["perf_all"] = @benchmarkable perf_all($X) +g["perf_any"] = @benchmarkable perf_any($Y) + +end # module