From 2b75515a9746fec9cda9d7fd07b8a03ac9c92d2e Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Mon, 10 Jan 2022 00:35:02 -0500 Subject: [PATCH 1/9] Implement various rate formats including fraction --- src/ProgressMeter.jl | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/ProgressMeter.jl b/src/ProgressMeter.jl index ed670fa..e10793f 100644 --- a/src/ProgressMeter.jl +++ b/src/ProgressMeter.jl @@ -4,6 +4,7 @@ using Printf: @sprintf using Distributed export Progress, ProgressThresh, ProgressUnknown, BarGlyphs, next!, update!, cancel, finish!, @showprogress, progress_map, progress_pmap, ijulia_behavior +export EmptyRateFormat, PercentageRateFormat, FractionalRateFormat, IntegralRateFormat """ `ProgressMeter` contains a suite of utilities for displaying progress @@ -213,6 +214,29 @@ ProgressUnknown(dt::Real, desc::AbstractString="Progress: ", ProgressUnknown(desc::AbstractString; kwargs...) = ProgressUnknown(desc=desc; kwargs...) +abstract type AbstractRateFormat end +function rate_string end + +struct EmptyRateFormat <: AbstractRateFormat end +rate_string(c::Int, n::Int, ::EmptyRateFormat) = "" + +struct PercentRateFormat <: AbstractRateFormat + digits::Int # number of digits below decimal point +end +function rate_string(c::Int, n::Int, p::PercentRateFormat) + if p.digits==0 + return lpad(round(Int, 100c/n), 3) * "%" + else + return lpad(round(100c/n, digits=p.digits), p.digits+4) * "%" # p.precision + 3, and +1 for "." + end +end + +struct FractionRateFormat <: AbstractRateFormat end +rate_string(c::Int, n::Int, ::FractionRateFormat) = lpad(c, length(string(n))) * "/" * string(n) + +struct IntegerRateFormat <: AbstractRateFormat end +rate_string(c::Int, n::Int, ::IntegerRateFormat) = lpad(c, length(string(n))) * " out of " * string(n) + #...length of percentage and ETA string with days is 29 characters, speed string is always 14 extra characters function tty_width(desc, output, showspeed::Bool) full_width = displaysize(output)[2] @@ -253,7 +277,7 @@ end # update progress display function updateProgress!(p::Progress; showvalues = (), truncate_lines = false, valuecolor = :blue, offset::Integer = p.offset, keep = (offset == 0), desc::Union{Nothing,AbstractString} = nothing, - ignore_predictor = false) + ignore_predictor = false, rate_format=PercentRateFormat(0)) !p.enabled && return if p.counter == 2 # ignore the first loop given usually uncharacteristically slow p.tsecond = time() @@ -273,7 +297,8 @@ function updateProgress!(p::Progress; showvalues = (), truncate_lines = false, v bar = barstring(barlen, percentage_complete, barglyphs=p.barglyphs) elapsed_time = t - p.tinit dur = durationstring(elapsed_time) - msg = @sprintf "%s%3u%%%s Time: %s" p.desc round(Int, percentage_complete) bar dur + rate_str = rate_string(p.counter, p.n, rate_format) + msg = @sprintf "%s%s%s Time: %s" p.desc rate_str bar dur if p.showspeed sec_per_iter = elapsed_time / (p.counter - p.start) msg = @sprintf "%s (%s)" msg speedstring(sec_per_iter) @@ -308,7 +333,8 @@ function updateProgress!(p::Progress; showvalues = (), truncate_lines = false, v else eta = "N/A" end - msg = @sprintf "%s%3u%%%s ETA: %s" p.desc round(Int, percentage_complete) bar eta + rate_str = rate_string(p.counter, p.n, rate_format) + msg = @sprintf "%s%s%s Time: %s" p.desc rate_str bar eta if p.showspeed sec_per_iter = elapsed_time / (p.counter - p.start) msg = @sprintf "%s (%s)" msg speedstring(sec_per_iter) From 205e7fffd251fa9bf847af756e4cf33392d75c0c Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Mon, 10 Jan 2022 12:58:17 -0500 Subject: [PATCH 2/9] Fix names of exported AbstractRateFormat types --- src/ProgressMeter.jl | 48 ++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/ProgressMeter.jl b/src/ProgressMeter.jl index e10793f..35a3283 100644 --- a/src/ProgressMeter.jl +++ b/src/ProgressMeter.jl @@ -4,7 +4,7 @@ using Printf: @sprintf using Distributed export Progress, ProgressThresh, ProgressUnknown, BarGlyphs, next!, update!, cancel, finish!, @showprogress, progress_map, progress_pmap, ijulia_behavior -export EmptyRateFormat, PercentageRateFormat, FractionalRateFormat, IntegralRateFormat +export EmptyRateFormat, PercentRateFormat, FractionRateFormat, IntegerRateFormat """ `ProgressMeter` contains a suite of utilities for displaying progress @@ -47,6 +47,29 @@ function BarGlyphs(s::AbstractString) return BarGlyphs(glyphs...) end +abstract type AbstractRateFormat end +function rate_string end + +struct EmptyRateFormat <: AbstractRateFormat end +rate_string(c::Int, n::Int, ::EmptyRateFormat) = "" + +struct PercentRateFormat <: AbstractRateFormat + digits::Int # number of digits below decimal point +end +function rate_string(c::Int, n::Int, p::PercentRateFormat) + if p.digits==0 + return lpad(round(Int, 100c/n), 3) * "%" + else + return lpad(round(100c/n, digits=p.digits), p.digits+4) * "%" # p.precision + 3, and +1 for "." + end +end + +struct FractionRateFormat <: AbstractRateFormat end +rate_string(c::Int, n::Int, ::FractionRateFormat) = lpad(c, length(string(n))) * "/" * string(n) + +struct IntegerRateFormat <: AbstractRateFormat end +rate_string(c::Int, n::Int, ::IntegerRateFormat) = lpad(c, length(string(n))) * " out of " * string(n) + """ `prog = Progress(n; dt=0.1, desc="Progress: ", color=:green, output=stderr, barlen=tty_width(desc), start=0)` creates a progress meter for a @@ -214,29 +237,6 @@ ProgressUnknown(dt::Real, desc::AbstractString="Progress: ", ProgressUnknown(desc::AbstractString; kwargs...) = ProgressUnknown(desc=desc; kwargs...) -abstract type AbstractRateFormat end -function rate_string end - -struct EmptyRateFormat <: AbstractRateFormat end -rate_string(c::Int, n::Int, ::EmptyRateFormat) = "" - -struct PercentRateFormat <: AbstractRateFormat - digits::Int # number of digits below decimal point -end -function rate_string(c::Int, n::Int, p::PercentRateFormat) - if p.digits==0 - return lpad(round(Int, 100c/n), 3) * "%" - else - return lpad(round(100c/n, digits=p.digits), p.digits+4) * "%" # p.precision + 3, and +1 for "." - end -end - -struct FractionRateFormat <: AbstractRateFormat end -rate_string(c::Int, n::Int, ::FractionRateFormat) = lpad(c, length(string(n))) * "/" * string(n) - -struct IntegerRateFormat <: AbstractRateFormat end -rate_string(c::Int, n::Int, ::IntegerRateFormat) = lpad(c, length(string(n))) * " out of " * string(n) - #...length of percentage and ETA string with days is 29 characters, speed string is always 14 extra characters function tty_width(desc, output, showspeed::Bool) full_width = displaysize(output)[2] From e86f0dce2fef58d49741671d7181fadef68a780c Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Mon, 10 Jan 2022 12:58:46 -0500 Subject: [PATCH 3/9] Add rate_format to Progress --- src/ProgressMeter.jl | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/ProgressMeter.jl b/src/ProgressMeter.jl index 35a3283..416e417 100644 --- a/src/ProgressMeter.jl +++ b/src/ProgressMeter.jl @@ -90,6 +90,7 @@ mutable struct Progress <: AbstractProgress tlast::Float64 printed::Bool # true if we have issued at least one status update desc::String # prefix to the percentage, e.g. "Computing..." + rate_format::AbstractRateFormat barlen::Union{Int,Nothing} # progress bar size (default is available terminal width) barglyphs::BarGlyphs # the characters to be used in the bar color::Symbol # default to green @@ -106,6 +107,7 @@ mutable struct Progress <: AbstractProgress function Progress(n::Integer; dt::Real=0.1, desc::AbstractString="Progress: ", + rate_format=PercentRateFormat(0), color::Symbol=:green, output::IO=stderr, barlen=nothing, @@ -120,17 +122,20 @@ mutable struct Progress <: AbstractProgress counter = start tinit = tsecond = tlast = time() printed = false - new(n, reentrantlocker, dt, counter, tinit, tsecond, tlast, printed, desc, barlen, barglyphs, color, output, offset, 0, start, enabled, showspeed, 1, 1, Int[]) + new(n, reentrantlocker, dt, counter, tinit, tsecond, tlast, printed, desc, rate_format, barlen, barglyphs, color, output, offset, 0, start, enabled, showspeed, 1, 1, Int[]) end end Progress(n::Integer, dt::Real, desc::AbstractString="Progress: ", + rate_format::AbstractRateFormat=PercentRateFormat(0), barlen=nothing, color::Symbol=:green, output::IO=stderr; offset::Integer=0) = - Progress(n, dt=dt, desc=desc, barlen=barlen, color=color, output=output, offset=offset) + Progress(n, dt=dt, desc=desc, rate_format=rate_format, barlen=barlen, color=color, output=output, offset=offset) Progress(n::Integer, desc::AbstractString, offset::Integer=0) = Progress(n, desc=desc, offset=offset) +Progress(n::Integer, desc::AbstractString, rate_format::AbstractRateFormat, offset::Integer=0) = + Progress(n, desc=desc, rate_format=rate_format, offset=offset) """ `prog = ProgressThresh(thresh; dt=0.1, desc="Progress: ", @@ -277,7 +282,7 @@ end # update progress display function updateProgress!(p::Progress; showvalues = (), truncate_lines = false, valuecolor = :blue, offset::Integer = p.offset, keep = (offset == 0), desc::Union{Nothing,AbstractString} = nothing, - ignore_predictor = false, rate_format=PercentRateFormat(0)) + ignore_predictor = false) !p.enabled && return if p.counter == 2 # ignore the first loop given usually uncharacteristically slow p.tsecond = time() @@ -297,7 +302,7 @@ function updateProgress!(p::Progress; showvalues = (), truncate_lines = false, v bar = barstring(barlen, percentage_complete, barglyphs=p.barglyphs) elapsed_time = t - p.tinit dur = durationstring(elapsed_time) - rate_str = rate_string(p.counter, p.n, rate_format) + rate_str = rate_string(p.counter, p.n, p.rate_format) msg = @sprintf "%s%s%s Time: %s" p.desc rate_str bar dur if p.showspeed sec_per_iter = elapsed_time / (p.counter - p.start) @@ -333,7 +338,7 @@ function updateProgress!(p::Progress; showvalues = (), truncate_lines = false, v else eta = "N/A" end - rate_str = rate_string(p.counter, p.n, rate_format) + rate_str = rate_string(p.counter, p.n, p.rate_format) msg = @sprintf "%s%s%s Time: %s" p.desc rate_str bar eta if p.showspeed sec_per_iter = elapsed_time / (p.counter - p.start) From c719788a33ce8785132b64a7a298452900375ca5 Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Mon, 10 Jan 2022 14:05:26 -0500 Subject: [PATCH 4/9] Make tests pass --- src/ProgressMeter.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ProgressMeter.jl b/src/ProgressMeter.jl index 416e417..573902d 100644 --- a/src/ProgressMeter.jl +++ b/src/ProgressMeter.jl @@ -127,7 +127,12 @@ mutable struct Progress <: AbstractProgress end Progress(n::Integer, dt::Real, desc::AbstractString="Progress: ", - rate_format::AbstractRateFormat=PercentRateFormat(0), + barlen=nothing, color::Symbol=:green, output::IO=stderr; + offset::Integer=0) = + Progress(n, dt=dt, desc=desc, barlen=barlen, color=color, output=output, offset=offset) + +Progress(n::Integer, dt::Real, desc::AbstractString="Progress: ", + rate_format::AbstractRateFormat=PercentRateFormat(), barlen=nothing, color::Symbol=:green, output::IO=stderr; offset::Integer=0) = Progress(n, dt=dt, desc=desc, rate_format=rate_format, barlen=barlen, color=color, output=output, offset=offset) From f24a42a774ed9925f49d7506a182f82ff7e66d83 Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Mon, 10 Jan 2022 14:06:20 -0500 Subject: [PATCH 5/9] Define default constructor for PercentRateFromat() --- src/ProgressMeter.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ProgressMeter.jl b/src/ProgressMeter.jl index 573902d..bd37618 100644 --- a/src/ProgressMeter.jl +++ b/src/ProgressMeter.jl @@ -56,6 +56,7 @@ rate_string(c::Int, n::Int, ::EmptyRateFormat) = "" struct PercentRateFormat <: AbstractRateFormat digits::Int # number of digits below decimal point end +PercentRateFormat() = PercentRateFormat(0) function rate_string(c::Int, n::Int, p::PercentRateFormat) if p.digits==0 return lpad(round(Int, 100c/n), 3) * "%" @@ -107,7 +108,7 @@ mutable struct Progress <: AbstractProgress function Progress(n::Integer; dt::Real=0.1, desc::AbstractString="Progress: ", - rate_format=PercentRateFormat(0), + rate_format=PercentRateFormat(), color::Symbol=:green, output::IO=stderr, barlen=nothing, From 0f85b006e817d27c448b9b06e59e01730e4a48b3 Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Sat, 15 Jan 2022 22:51:05 -0500 Subject: [PATCH 6/9] Improve formatting for PercentRateFormat --- src/ProgressMeter.jl | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ProgressMeter.jl b/src/ProgressMeter.jl index bd37618..e134efb 100644 --- a/src/ProgressMeter.jl +++ b/src/ProgressMeter.jl @@ -58,11 +58,14 @@ struct PercentRateFormat <: AbstractRateFormat end PercentRateFormat() = PercentRateFormat(0) function rate_string(c::Int, n::Int, p::PercentRateFormat) - if p.digits==0 - return lpad(round(Int, 100c/n), 3) * "%" - else - return lpad(round(100c/n, digits=p.digits), p.digits+4) * "%" # p.precision + 3, and +1 for "." - end + str = string(round(100c/n, digits=p.digits)) # e.g., round(10, digits=0) = 10.0 + i, f = split(str, ".") # integral, fractional parts + + rate_str = lpad(i, 3) + p.digits≠0 && (rate_str *= "." * rpad(f, p.digits, "0")) + rate_str *= "%" + + return rate_str end struct FractionRateFormat <: AbstractRateFormat end From dd5d2ced622f338164a1d95494bc112bc9772038 Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Sat, 15 Jan 2022 22:51:34 -0500 Subject: [PATCH 7/9] Simplify formatting for IntegerRateFormat --- src/ProgressMeter.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ProgressMeter.jl b/src/ProgressMeter.jl index e134efb..c59ebce 100644 --- a/src/ProgressMeter.jl +++ b/src/ProgressMeter.jl @@ -72,7 +72,7 @@ struct FractionRateFormat <: AbstractRateFormat end rate_string(c::Int, n::Int, ::FractionRateFormat) = lpad(c, length(string(n))) * "/" * string(n) struct IntegerRateFormat <: AbstractRateFormat end -rate_string(c::Int, n::Int, ::IntegerRateFormat) = lpad(c, length(string(n))) * " out of " * string(n) +rate_string(c::Int, n::Int, ::IntegerRateFormat) = lpad(c, length(string(n))) * " of " * string(n) """ `prog = Progress(n; dt=0.1, desc="Progress: ", color=:green, From 6ce9b935f2459ec03396beb1c6910dda6f53a65f Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Sat, 15 Jan 2022 22:52:52 -0500 Subject: [PATCH 8/9] Add tests for rate format --- test/test.jl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test.jl b/test/test.jl index e4c4ecc..af75d6d 100644 --- a/test/test.jl +++ b/test/test.jl @@ -82,6 +82,20 @@ end println("\nTesting changing the description") testfunc5B(107, 0.01, 0.05, "Step 1...", 50) +function testfunc5C(n, dt, tsleep, desc, rate_format) + p = ProgressMeter.Progress(n, dt, desc, rate_format) + for i = 1:n + sleep(tsleep) + ProgressMeter.next!(p) + end +end + +println("\nTesting changing the progress rate format") +testfunc5C(107, 0.01, 0.05, "Computing...", EmptyRateFormat()) +testfunc5C(107, 0.01, 0.05, "Computing...", PercentRateFormat()) +testfunc5C(107, 0.01, 0.05, "Computing...", PercentRateFormat(2)) +testfunc5C(107, 0.01, 0.05, "Computing...", FractionRateFormat()) +testfunc5C(107, 0.01, 0.05, "Computing...", IntegerRateFormat()) function testfunc6(n, dt, tsleep) ProgressMeter.@showprogress dt for i in 1:n From 77e5ea2dc73ab83ab77cac137f57c8881ce2c4bc Mon Sep 17 00:00:00 2001 From: Wonseok Shin Date: Sat, 15 Jan 2022 23:29:58 -0500 Subject: [PATCH 9/9] Add usages for different rate formats in README --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index b9026b7..c8ccfcc 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,29 @@ The first incantation will use a minimum update interval of 1 second, and show t final duration. If your computation runs so quickly that it never needs to show progress, no extraneous output will be displayed. +Different formats for progress rate string are supported: +```julia +# Empty string +@showprogress 1 "Computing..." EmptyRateFormat() for i in 1:107 + sleep(0.1) +end + +# 2 digits below decimal point (e.g., "2.80%") +@showprogress 1 "Computing..." PercentRateFormat(2) for i in 1:107 + sleep(0.1) +end + +# Fraction (e.g., "3/107") +@showprogress 1 "Computing..." FractionRateFormat() for i in 1:107 + sleep(0.1) +end + +# Integer (e.g., "3 of 107") +@showprogress 1 "Computing..." IntegerRateFormat() for i in 1:107 + sleep(0.1) +end +``` + The `@showprogress` macro wraps a `for` loop, comprehension, `@distributed` for loop, or `map`/`pmap`/`reduce` as long as the object being iterated over implements the `length` method and will handle `continue` correctly.