From 9dbc3f94144fc72514940fe41dc27f55dfe33d77 Mon Sep 17 00:00:00 2001 From: Sergey Fokin Date: Fri, 2 Jul 2021 04:03:08 +0100 Subject: [PATCH] show(io, float) optimization --- base/ryu/Ryu.jl | 44 +++++++++++++++++++++++++------------------- base/ryu/shortest.jl | 2 +- base/scratch.jl | 38 ++++++++++++++++++++++++++++++++++---- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/base/ryu/Ryu.jl b/base/ryu/Ryu.jl index 81d1c41f4c19f..4b53bc80e3ed9 100644 --- a/base/ryu/Ryu.jl +++ b/base/ryu/Ryu.jl @@ -1,6 +1,7 @@ module Ryu import .Base: significand_bits, significand_mask, exponent_bits, exponent_mask, exponent_bias, exponent_max, uinttype +import .Base: with_scratch include("utils.jl") include("shortest.jl") @@ -45,9 +46,10 @@ function writeshortest(x::T, decchar::UInt8=UInt8('.'), typed::Bool=false, compact::Bool=false) where {T <: Base.IEEEFloat} - buf = Base.StringVector(neededdigits(T)) - pos = writeshortest(buf, 1, x, plus, space, hash, precision, expchar, padexp, decchar, typed, compact) - return String(resize!(buf, pos - 1)) + with_scratch(neededdigits(T)) do buf + pos = writeshortest(buf, 1, x, plus, space, hash, precision, expchar, padexp, decchar, typed, compact) + return String(@inbounds view(buf, 1:pos - 1)) + end end """ @@ -73,9 +75,10 @@ function writefixed(x::T, hash::Bool=false, decchar::UInt8=UInt8('.'), trimtrailingzeros::Bool=false) where {T <: Base.IEEEFloat} - buf = Base.StringVector(precision + neededdigits(T)) - pos = writefixed(buf, 1, x, precision, plus, space, hash, decchar, trimtrailingzeros) - return String(resize!(buf, pos - 1)) + with_scratch(precision + neededdigits(T)) do buf + pos = writefixed(buf, 1, x, precision, plus, space, hash, decchar, trimtrailingzeros) + return String(@inbounds view(buf, 1:pos - 1)) + end end """ @@ -103,26 +106,29 @@ function writeexp(x::T, expchar::UInt8=UInt8('e'), decchar::UInt8=UInt8('.'), trimtrailingzeros::Bool=false) where {T <: Base.IEEEFloat} - buf = Base.StringVector(precision + neededdigits(T)) - pos = writeexp(buf, 1, x, precision, plus, space, hash, expchar, decchar, trimtrailingzeros) - return String(resize!(buf, pos - 1)) + with_scratch(precision + neededdigits(T)) do buf + pos = writeexp(buf, 1, x, precision, plus, space, hash, expchar, decchar, trimtrailingzeros) + return String(@inbounds view(buf, 1:pos - 1)) + end end function Base.show(io::IO, x::T, forceuntyped::Bool=false, fromprint::Bool=false) where {T <: Base.IEEEFloat} compact = get(io, :compact, false)::Bool - buf = Base.StringVector(neededdigits(T)) - typed = !forceuntyped && !compact && get(io, :typeinfo, Any) != typeof(x) - pos = writeshortest(buf, 1, x, false, false, true, -1, - (x isa Float32 && !fromprint) ? UInt8('f') : UInt8('e'), false, UInt8('.'), typed, compact) - write(io, resize!(buf, pos - 1)) - return + with_scratch(neededdigits(T)) do buf + typed = !forceuntyped && !compact && get(io, :typeinfo, Any) != typeof(x) + pos = writeshortest(buf, 1, x, false, false, true, -1, + (x isa Float32 && !fromprint) ? UInt8('f') : UInt8('e'), false, UInt8('.'), typed, compact) + write(io, @inbounds view(buf, 1:pos - 1)) + return + end end function Base.string(x::T) where {T <: Base.IEEEFloat} - buf = Base.StringVector(neededdigits(T)) - pos = writeshortest(buf, 1, x, false, false, true, -1, - UInt8('e'), false, UInt8('.'), false, false) - return String(resize!(buf, pos - 1)) + with_scratch(neededdigits(T)) do buf + pos = writeshortest(buf, 1, x, false, false, true, -1, + UInt8('e'), false, UInt8('.'), false, false) + return String(@inbounds view(buf, 1:pos - 1)) + end end Base.print(io::IO, x::Union{Float16, Float32}) = show(io, x, true, true) diff --git a/base/ryu/shortest.jl b/base/ryu/shortest.jl index f95c09d235e6d..401de99227ca5 100644 --- a/base/ryu/shortest.jl +++ b/base/ryu/shortest.jl @@ -224,7 +224,7 @@ integer. If a `maxsignif` argument is provided, then `b < maxsignif`. return b, e10 end -function writeshortest(buf::Vector{UInt8}, pos, x::T, +function writeshortest(buf, pos, x::T, plus=false, space=false, hash=true, precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'), typed=false, compact=false) where {T} diff --git a/base/scratch.jl b/base/scratch.jl index f9fc44cb5ce55..c3389953d9af4 100644 --- a/base/scratch.jl +++ b/base/scratch.jl @@ -1,4 +1,5 @@ -const PRINT_SCRATCH_LENGTH = 256 +# NOTE: ryu/Ryu.jl: neededdigits(::Type{Float64}) = 309 + 17 +const PRINT_SCRATCH_LENGTH = 309 + 17 struct ScratchBuf data::NTuple{PRINT_SCRATCH_LENGTH,UInt8} @@ -11,16 +12,45 @@ struct Scratch end function with_scratch(f, n) - buf = Ref(ScratchBuf(undef)) - GC.@preserve buf f(Scratch(pointer_from_objref(buf), unsafe_trunc(UInt64, n))) + if n <= PRINT_SCRATCH_LENGTH + buf = Ref(ScratchBuf(undef)) + GC.@preserve buf f(Scratch(pointer_from_objref(buf), unsafe_trunc(UInt64, n))) + else + tls = task_local_storage() + buf = get!(tls, :PRINT_SCRATCH) do + Vector{UInt8}(undef, n) + end::Vector{UInt8} + resize!(buf, n) + GC.@preserve buf f(Scratch(pointer(buf), length(buf))) + end end @propagate_inbounds function setindex!(a::Scratch, v, i) - @boundscheck (i <= a.length || throw(BoundsError(a, i))) + @boundscheck (1 <= i <= a.length || throw(BoundsError(a, i))) unsafe_store!(a.p, convert(UInt8, v), i) a end +@propagate_inbounds function getindex(a::Scratch, i) + @boundscheck (1 <= i <= a.length || throw(BoundsError(a, i))) + unsafe_load(a.p, i) +end + +@propagate_inbounds function view(a::Scratch, index::UnitRange) + @boundscheck ((index.start > 0 && index.stop <= a.length) || throw(BoundsError)) + index.start > index.stop && return Scratch(Ptr{UInt8}(), 0) + Scratch(a.p + index.start - 1, unsafe_trunc(UInt64, index.stop - index.start + 1)) +end + +pointer(a::Scratch) = a.p +pointer(a::Scratch, pos) = a.p + pos - 1 +length(a::Scratch) = a.length +@inline function unsafe_copyto!(dst::Scratch, dst_pos, src::Vector{UInt8}, src_pos, N) + GC.@preserve dst, src, begin + unsafe_copyto!(pointer(dst, dst_pos), pointer(src, src_pos), N) + end +end + write(io::IO, a::Scratch) = unsafe_write(io, a.p, a.length) String(s::Scratch) = unsafe_string(s.p, s.length)