Skip to content

Commit

Permalink
Drop Julia <1.6. Reduce code duplication by introducing ProgressCore (#…
Browse files Browse the repository at this point in the history
…304)

* reduce duplication by introducing ProgressCore

* drop julia <1.6

* update caching

* fix

* CI tweaks

* suggestions

* Update ProgressMeter.jl

* typo
  • Loading branch information
IanButterworth authored Mar 3, 2024
1 parent 7e2bbca commit 55425a0
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 139 deletions.
24 changes: 6 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@ on:
tags: '*'
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
version:
- '0.7'
- '1.0'
- '1.6'
- '1'
- 'nightly'
os:
Expand All @@ -25,30 +23,20 @@ jobs:
- windows-latest
arch:
- x64
nthreads:
- 1
- 2
steps:
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: actions/cache@v4
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
- uses: julia-actions/cache@v1
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
env:
JULIA_NUM_THREADS: 1
- uses: julia-actions/julia-runtest@v1
if: ${{ matrix.version != '0.7' && matrix.version != '1.0' }}
env:
JULIA_NUM_THREADS: 2
JULIA_NUM_THREADS: ${{ matrix.nthreads }}
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[compat]
julia = "0.7, 1"
julia = "1.6"

[extras]
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
Expand Down
206 changes: 86 additions & 120 deletions src/ProgressMeter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,29 @@ function BarGlyphs(s::AbstractString)
end
return BarGlyphs(glyphs...)
end
const defaultglyphs = BarGlyphs('|','', Sys.iswindows() ? '' : ['','','','','','',''],' ','|',)

# Internal struct for holding common properties and internals for progress meters
Base.@kwdef mutable struct ProgressCore
color::Symbol = :green # color of the meter
desc::String = "Progress: " # prefix to the percentage, e.g. "Computing..."
dt::Real = Float64(0.1) # minimum time between updates
enabled::Bool = true # is the output enabled
offset::Int = 0 # position offset of progress bar (default is 0)
output::IO = stderr # output stream into which the progress is written
showspeed::Bool = false # should the output include average time per iteration
# internals
check_iterations::Int = 1 # number of iterations to check time for
counter::Int = 0 # current iteration
lock::Threads.ReentrantLock = Threads.ReentrantLock() # lock used when threading detected
numprintedvalues::Int = 0 # num values printed below progress in last iteration
prev_update_count::Int = 1 # counter at last update
printed::Bool = false # true if we have issued at least one status update
threads_used::Vector{Int} = Int[] # threads that have used this progress meter
tinit::Float64 = time() # time meter was initialized
tlast::Float64 = time() # time of last update
tsecond::Float64 = time() # ignore the first loop given usually uncharacteristically slow
end

"""
`prog = Progress(n; dt=0.1, desc="Progress: ", color=:green,
Expand All @@ -57,46 +80,37 @@ the current task. Optionally you can disable the progress bar by setting
"(12.34 ms/it)" to the description by setting `showspeed=true`.
"""
mutable struct Progress <: AbstractProgress
n::Int
reentrantlocker::Threads.ReentrantLock
dt::Float64
counter::Int
tinit::Float64
tsecond::Float64 # ignore the first loop given usually uncharacteristically slow
tlast::Float64
printed::Bool # true if we have issued at least one status update
desc::String # prefix to the percentage, e.g. "Computing..."
n::Int # total number of iterations
start::Int # which iteration number to start from
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
output::IO # output stream into which the progress is written
offset::Int # position offset of progress bar (default is 0)
numprintedvalues::Int # num values printed below progress in last iteration
start::Int # which iteration number to start from
enabled::Bool # is the output enabled
showspeed::Bool # should the output include average time per iteration
check_iterations::Int
prev_update_count::Int
threads_used::Vector{Int}

function Progress(n::Integer;
dt::Real=0.1,
desc::AbstractString="Progress: ",
color::Symbol=:green,
output::IO=stderr,
barlen=nothing,
barglyphs::BarGlyphs=BarGlyphs('|','', Sys.iswindows() ? '' : ['','','','','','',''],' ','|',),
offset::Integer=0,
start::Integer=0,
enabled::Bool = true,
showspeed::Bool = false,
)
barglyphs::BarGlyphs # the characters to be used in the bar
# internals
core::ProgressCore

function Progress(
n::Integer;
start::Integer=0,
barlen::Union{Int,Nothing}=nothing,
barglyphs::BarGlyphs=defaultglyphs,
kwargs...)
CLEAR_IJULIA[] = clear_ijulia()
reentrantlocker = Threads.ReentrantLock()
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[])
core = ProgressCore(;kwargs...)
new(n, start, barlen, barglyphs, core)
end
end
# forward common core properties to main types
function Base.setproperty!(p::T, name::Symbol, value) where T<:AbstractProgress
if hasfield(T, name)
setfield!(p, name, value)
else
setproperty!(p.core, name, value)
end
end
function Base.getproperty(p::T, name::Symbol) where T<:AbstractProgress
if hasfield(T, name)
getfield(p, name)
else
getproperty(p.core, name)
end
end

Expand All @@ -112,39 +126,16 @@ per-iteration average duration like "(12.34 ms/it)" to the description by
setting `showspeed=true`.
"""
mutable struct ProgressThresh{T<:Real} <: AbstractProgress
thresh::T
reentrantlocker::Threads.ReentrantLock
dt::Float64
val::T
counter::Int
triggered::Bool
tinit::Float64
tlast::Float64
printed::Bool # true if we have issued at least one status update
desc::String # prefix to the percentage, e.g. "Computing..."
color::Symbol # default to green
output::IO # output stream into which the progress is written
numprintedvalues::Int # num values printed below progress in last iteration
offset::Int # position offset of progress bar (default is 0)
enabled::Bool # is the output enabled
showspeed::Bool # should the output include average time per iteration
check_iterations::Int
prev_update_count::Int
threads_used::Vector{Int}

function ProgressThresh{T}(thresh;
dt::Real=0.1,
desc::AbstractString="Progress: ",
color::Symbol=:green,
output::IO=stderr,
offset::Integer=0,
enabled = true,
showspeed::Bool = false) where T
thresh::T # termination threshold
val::T # current value
# internals
triggered::Bool # has the threshold been reached?
core::ProgressCore # common properties and internals

function ProgressThresh{T}(thresh; val::T=typemax(T), triggered::Bool=false, kwargs...) where T
CLEAR_IJULIA[] = clear_ijulia()
reentrantlocker = Threads.ReentrantLock()
tinit = tlast = time()
printed = false
new{T}(thresh, reentrantlocker, dt, typemax(T), 0, false, tinit, tlast, printed, desc, color, output, 0, offset, enabled, showspeed, 1, 1, Int[])
core = ProgressCore(;kwargs...)
new{T}(thresh, val, triggered, core)
end
end
ProgressThresh(thresh::Real; kwargs...) = ProgressThresh{typeof(thresh)}(thresh; kwargs...)
Expand All @@ -163,42 +154,17 @@ setting `showspeed=true`. Instead of displaying a counter, it
can optionally display a spinning ball by passing `spinner=true`.
"""
mutable struct ProgressUnknown <: AbstractProgress
done::Bool
reentrantlocker::Threads.ReentrantLock
dt::Float64
counter::Int
spincounter::Int
triggered::Bool
tinit::Float64
tlast::Float64
printed::Bool # true if we have issued at least one status update
desc::String # prefix to the percentage, e.g. "Computing..."
color::Symbol # default to green
# internals
done::Bool # is the task done?
spinner::Bool # show a spinner
output::IO # output stream into which the progress is written
numprintedvalues::Int # num values printed below progress in last iteration
offset::Int # position offset of progress bar (default is 0)
enabled::Bool # is the output enabled
showspeed::Bool # should the output include average time per iteration
check_iterations::Int
prev_update_count::Int
threads_used::Vector{Int}
end
spincounter::Int # counter for spinner
core::ProgressCore # common properties and internals

function ProgressUnknown(;
dt::Real=0.1,
desc::AbstractString="Progress: ",
color::Symbol=:green,
spinner::Bool=false,
output::IO=stderr,
offset::Integer=0,
enabled::Bool = true,
showspeed::Bool = false)
CLEAR_IJULIA[] = clear_ijulia()
reentrantlocker = Threads.ReentrantLock()
tinit = tlast = time()
printed = false
ProgressUnknown(false, reentrantlocker, dt, 0, 0, false, tinit, tlast, printed, desc, color, spinner, output, 0, offset, enabled, showspeed, 1, 1, Int[])
function ProgressUnknown(; spinner::Bool=false, kwargs...)
CLEAR_IJULIA[] = clear_ijulia()
core = ProgressCore(;kwargs...)
new(false, spinner, 0, core)
end
end

#...length of percentage and ETA string with days is 29 characters, speed string is always 14 extra characters
Expand Down Expand Up @@ -239,9 +205,9 @@ function calc_check_iterations(p, t)
end

# update progress display
function updateProgress!(p::Progress; showvalues = (),
function updateProgress!(p::Progress; showvalues = (),
truncate_lines = false, valuecolor = :blue,
offset::Integer = p.offset, keep = (offset == 0),
offset::Integer = p.offset, keep = (offset == 0),
desc::Union{Nothing,AbstractString} = nothing,
ignore_predictor = false, color = p.color, max_steps = p.n)
!p.enabled && return
Expand Down Expand Up @@ -326,9 +292,9 @@ function updateProgress!(p::Progress; showvalues = (),
return nothing
end

function updateProgress!(p::ProgressThresh; showvalues = (),
function updateProgress!(p::ProgressThresh; showvalues = (),
truncate_lines = false, valuecolor = :blue,
offset::Integer = p.offset, keep = (offset == 0),
offset::Integer = p.offset, keep = (offset == 0),
desc = p.desc, ignore_predictor = false,
color = p.color, thresh = p.thresh)
!p.enabled && return
Expand Down Expand Up @@ -484,7 +450,7 @@ end

function lock_if_threading(f::Function, p::AbstractProgress)
if is_threading(p)
lock(p.reentrantlocker) do
lock(p.lock) do
f()
end
else
Expand Down Expand Up @@ -549,8 +515,8 @@ the message printed and its color.
See also `finish!`.
"""
function cancel(p::AbstractProgress, msg::AbstractString = "Aborted before all tasks were completed";
color = :red, showvalues = (), truncate_lines = false,
function cancel(p::AbstractProgress, msg::AbstractString = "Aborted before all tasks were completed";
color = :red, showvalues = (), truncate_lines = false,
valuecolor = :blue, offset = p.offset, keep = (offset == 0))
lock_if_threading(p) do
p.offset = offset
Expand Down Expand Up @@ -863,13 +829,13 @@ end
@showprogress [desc="Computing..."] pmap(x->x^2, 1:50)
```
displays progress in performing a computation. You may optionally
supply a custom message to be printed that specifies the computation
displays progress in performing a computation. You may optionally
supply a custom message to be printed that specifies the computation
being performed or other options.
`@showprogress` works for loops, comprehensions, and `map`-like
`@showprogress` works for loops, comprehensions, and `map`-like
functions. These `map`-like functions rely on `ncalls` being defined
and can be checked with `methods(ProgressMeter.ncalls)`. New ones can
and can be checked with `methods(ProgressMeter.ncalls)`. New ones can
be added by defining `ProgressMeter.ncalls(::typeof(mapfun), args...) = ...`.
`@showprogress` is thread-safe and will work with `@distributed` loops
Expand All @@ -891,7 +857,7 @@ function showprogress(args...)
throw(ArgumentError("Final argument to @showprogress must be a for loop, comprehension, or a map-like function; got $expr"))
end

if expr.head == :call && expr.args[1] == :|>
if expr.head == :call && expr.args[1] == :|>
# e.g. map(x->x^2) |> sum
expr.args[2] = showprogress(progressargs..., expr.args[2])
return expr
Expand All @@ -908,7 +874,7 @@ function showprogress(args...)
elseif expr.head == :macrocall
macroname = expr.args[1]

if macroname in (Symbol("@distributed"), :(Distributed.@distributed).args[1])
if macroname in (Symbol("@distributed"), :(Distributed.@distributed).args[1])
# can be changed to `:(Distributed.var"@distributed")` if support for pre-1.3 is dropped
return showprogressdistributed(args...)

Expand Down Expand Up @@ -991,9 +957,9 @@ function showprogress_loop(expr, progressargs)
# Transform the first loop assignment
loopassign = expr.args[outerassignidx] = copy(expr.args[outerassignidx])

if loopassign.head === :filter
if loopassign.head === :filter
# e.g. [x for x=1:10, y=1:10 if x>y]
# y will be wrapped in ProgressWrapper
# y will be wrapped in ProgressWrapper
for i in 1:length(loopassign.args)-1
loopassign.args[i] = esc(loopassign.args[i])
end
Expand Down Expand Up @@ -1109,7 +1075,7 @@ to define the length of the `Progress` in `@showprogress` and `progress_map`.
Internally uses one of `ncalls_map`, `ncalls_broadcast(!)` or `ncalls_reduce` depending
on the type of `mapfun`.
Support for additional functions can be added by defining
Support for additional functions can be added by defining
`ProgressMeter.ncalls(::typeof(mapfun), ::Function, args...)`.
"""
ncalls(::typeof(map), ::Function, args...) = ncalls_map(args...)
Expand Down

0 comments on commit 55425a0

Please sign in to comment.