Skip to content

Commit 55425a0

Browse files
Drop Julia <1.6. Reduce code duplication by introducing ProgressCore (#304)
* reduce duplication by introducing ProgressCore * drop julia <1.6 * update caching * fix * CI tweaks * suggestions * Update ProgressMeter.jl * typo
1 parent 7e2bbca commit 55425a0

File tree

3 files changed

+93
-139
lines changed

3 files changed

+93
-139
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@ on:
99
tags: '*'
1010
jobs:
1111
test:
12-
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
1312
runs-on: ${{ matrix.os }}
1413
strategy:
1514
fail-fast: false
1615
matrix:
1716
version:
18-
- '0.7'
19-
- '1.0'
17+
- '1.6'
2018
- '1'
2119
- 'nightly'
2220
os:
@@ -25,30 +23,20 @@ jobs:
2523
- windows-latest
2624
arch:
2725
- x64
26+
nthreads:
27+
- 1
28+
- 2
2829
steps:
2930
- uses: actions/checkout@v4
3031
- uses: julia-actions/setup-julia@v1
3132
with:
3233
version: ${{ matrix.version }}
3334
arch: ${{ matrix.arch }}
34-
- uses: actions/cache@v4
35-
env:
36-
cache-name: cache-artifacts
37-
with:
38-
path: ~/.julia/artifacts
39-
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
40-
restore-keys: |
41-
${{ runner.os }}-test-${{ env.cache-name }}-
42-
${{ runner.os }}-test-
43-
${{ runner.os }}-
35+
- uses: julia-actions/cache@v1
4436
- uses: julia-actions/julia-buildpkg@v1
4537
- uses: julia-actions/julia-runtest@v1
4638
env:
47-
JULIA_NUM_THREADS: 1
48-
- uses: julia-actions/julia-runtest@v1
49-
if: ${{ matrix.version != '0.7' && matrix.version != '1.0' }}
50-
env:
51-
JULIA_NUM_THREADS: 2
39+
JULIA_NUM_THREADS: ${{ matrix.nthreads }}
5240
- uses: julia-actions/julia-processcoverage@v1
5341
- uses: codecov/codecov-action@v4
5442
with:

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
77
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
88

99
[compat]
10-
julia = "0.7, 1"
10+
julia = "1.6"
1111

1212
[extras]
1313
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"

src/ProgressMeter.jl

Lines changed: 86 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,29 @@ function BarGlyphs(s::AbstractString)
4545
end
4646
return BarGlyphs(glyphs...)
4747
end
48+
const defaultglyphs = BarGlyphs('|','', Sys.iswindows() ? '' : ['','','','','','',''],' ','|',)
49+
50+
# Internal struct for holding common properties and internals for progress meters
51+
Base.@kwdef mutable struct ProgressCore
52+
color::Symbol = :green # color of the meter
53+
desc::String = "Progress: " # prefix to the percentage, e.g. "Computing..."
54+
dt::Real = Float64(0.1) # minimum time between updates
55+
enabled::Bool = true # is the output enabled
56+
offset::Int = 0 # position offset of progress bar (default is 0)
57+
output::IO = stderr # output stream into which the progress is written
58+
showspeed::Bool = false # should the output include average time per iteration
59+
# internals
60+
check_iterations::Int = 1 # number of iterations to check time for
61+
counter::Int = 0 # current iteration
62+
lock::Threads.ReentrantLock = Threads.ReentrantLock() # lock used when threading detected
63+
numprintedvalues::Int = 0 # num values printed below progress in last iteration
64+
prev_update_count::Int = 1 # counter at last update
65+
printed::Bool = false # true if we have issued at least one status update
66+
threads_used::Vector{Int} = Int[] # threads that have used this progress meter
67+
tinit::Float64 = time() # time meter was initialized
68+
tlast::Float64 = time() # time of last update
69+
tsecond::Float64 = time() # ignore the first loop given usually uncharacteristically slow
70+
end
4871

4972
"""
5073
`prog = Progress(n; dt=0.1, desc="Progress: ", color=:green,
@@ -57,46 +80,37 @@ the current task. Optionally you can disable the progress bar by setting
5780
"(12.34 ms/it)" to the description by setting `showspeed=true`.
5881
"""
5982
mutable struct Progress <: AbstractProgress
60-
n::Int
61-
reentrantlocker::Threads.ReentrantLock
62-
dt::Float64
63-
counter::Int
64-
tinit::Float64
65-
tsecond::Float64 # ignore the first loop given usually uncharacteristically slow
66-
tlast::Float64
67-
printed::Bool # true if we have issued at least one status update
68-
desc::String # prefix to the percentage, e.g. "Computing..."
83+
n::Int # total number of iterations
84+
start::Int # which iteration number to start from
6985
barlen::Union{Int,Nothing} # progress bar size (default is available terminal width)
70-
barglyphs::BarGlyphs # the characters to be used in the bar
71-
color::Symbol # default to green
72-
output::IO # output stream into which the progress is written
73-
offset::Int # position offset of progress bar (default is 0)
74-
numprintedvalues::Int # num values printed below progress in last iteration
75-
start::Int # which iteration number to start from
76-
enabled::Bool # is the output enabled
77-
showspeed::Bool # should the output include average time per iteration
78-
check_iterations::Int
79-
prev_update_count::Int
80-
threads_used::Vector{Int}
81-
82-
function Progress(n::Integer;
83-
dt::Real=0.1,
84-
desc::AbstractString="Progress: ",
85-
color::Symbol=:green,
86-
output::IO=stderr,
87-
barlen=nothing,
88-
barglyphs::BarGlyphs=BarGlyphs('|','', Sys.iswindows() ? '' : ['','','','','','',''],' ','|',),
89-
offset::Integer=0,
90-
start::Integer=0,
91-
enabled::Bool = true,
92-
showspeed::Bool = false,
93-
)
86+
barglyphs::BarGlyphs # the characters to be used in the bar
87+
# internals
88+
core::ProgressCore
89+
90+
function Progress(
91+
n::Integer;
92+
start::Integer=0,
93+
barlen::Union{Int,Nothing}=nothing,
94+
barglyphs::BarGlyphs=defaultglyphs,
95+
kwargs...)
9496
CLEAR_IJULIA[] = clear_ijulia()
95-
reentrantlocker = Threads.ReentrantLock()
96-
counter = start
97-
tinit = tsecond = tlast = time()
98-
printed = false
99-
new(n, reentrantlocker, dt, counter, tinit, tsecond, tlast, printed, desc, barlen, barglyphs, color, output, offset, 0, start, enabled, showspeed, 1, 1, Int[])
97+
core = ProgressCore(;kwargs...)
98+
new(n, start, barlen, barglyphs, core)
99+
end
100+
end
101+
# forward common core properties to main types
102+
function Base.setproperty!(p::T, name::Symbol, value) where T<:AbstractProgress
103+
if hasfield(T, name)
104+
setfield!(p, name, value)
105+
else
106+
setproperty!(p.core, name, value)
107+
end
108+
end
109+
function Base.getproperty(p::T, name::Symbol) where T<:AbstractProgress
110+
if hasfield(T, name)
111+
getfield(p, name)
112+
else
113+
getproperty(p.core, name)
100114
end
101115
end
102116

@@ -112,39 +126,16 @@ per-iteration average duration like "(12.34 ms/it)" to the description by
112126
setting `showspeed=true`.
113127
"""
114128
mutable struct ProgressThresh{T<:Real} <: AbstractProgress
115-
thresh::T
116-
reentrantlocker::Threads.ReentrantLock
117-
dt::Float64
118-
val::T
119-
counter::Int
120-
triggered::Bool
121-
tinit::Float64
122-
tlast::Float64
123-
printed::Bool # true if we have issued at least one status update
124-
desc::String # prefix to the percentage, e.g. "Computing..."
125-
color::Symbol # default to green
126-
output::IO # output stream into which the progress is written
127-
numprintedvalues::Int # num values printed below progress in last iteration
128-
offset::Int # position offset of progress bar (default is 0)
129-
enabled::Bool # is the output enabled
130-
showspeed::Bool # should the output include average time per iteration
131-
check_iterations::Int
132-
prev_update_count::Int
133-
threads_used::Vector{Int}
134-
135-
function ProgressThresh{T}(thresh;
136-
dt::Real=0.1,
137-
desc::AbstractString="Progress: ",
138-
color::Symbol=:green,
139-
output::IO=stderr,
140-
offset::Integer=0,
141-
enabled = true,
142-
showspeed::Bool = false) where T
129+
thresh::T # termination threshold
130+
val::T # current value
131+
# internals
132+
triggered::Bool # has the threshold been reached?
133+
core::ProgressCore # common properties and internals
134+
135+
function ProgressThresh{T}(thresh; val::T=typemax(T), triggered::Bool=false, kwargs...) where T
143136
CLEAR_IJULIA[] = clear_ijulia()
144-
reentrantlocker = Threads.ReentrantLock()
145-
tinit = tlast = time()
146-
printed = false
147-
new{T}(thresh, reentrantlocker, dt, typemax(T), 0, false, tinit, tlast, printed, desc, color, output, 0, offset, enabled, showspeed, 1, 1, Int[])
137+
core = ProgressCore(;kwargs...)
138+
new{T}(thresh, val, triggered, core)
148139
end
149140
end
150141
ProgressThresh(thresh::Real; kwargs...) = ProgressThresh{typeof(thresh)}(thresh; kwargs...)
@@ -163,42 +154,17 @@ setting `showspeed=true`. Instead of displaying a counter, it
163154
can optionally display a spinning ball by passing `spinner=true`.
164155
"""
165156
mutable struct ProgressUnknown <: AbstractProgress
166-
done::Bool
167-
reentrantlocker::Threads.ReentrantLock
168-
dt::Float64
169-
counter::Int
170-
spincounter::Int
171-
triggered::Bool
172-
tinit::Float64
173-
tlast::Float64
174-
printed::Bool # true if we have issued at least one status update
175-
desc::String # prefix to the percentage, e.g. "Computing..."
176-
color::Symbol # default to green
157+
# internals
158+
done::Bool # is the task done?
177159
spinner::Bool # show a spinner
178-
output::IO # output stream into which the progress is written
179-
numprintedvalues::Int # num values printed below progress in last iteration
180-
offset::Int # position offset of progress bar (default is 0)
181-
enabled::Bool # is the output enabled
182-
showspeed::Bool # should the output include average time per iteration
183-
check_iterations::Int
184-
prev_update_count::Int
185-
threads_used::Vector{Int}
186-
end
160+
spincounter::Int # counter for spinner
161+
core::ProgressCore # common properties and internals
187162

188-
function ProgressUnknown(;
189-
dt::Real=0.1,
190-
desc::AbstractString="Progress: ",
191-
color::Symbol=:green,
192-
spinner::Bool=false,
193-
output::IO=stderr,
194-
offset::Integer=0,
195-
enabled::Bool = true,
196-
showspeed::Bool = false)
197-
CLEAR_IJULIA[] = clear_ijulia()
198-
reentrantlocker = Threads.ReentrantLock()
199-
tinit = tlast = time()
200-
printed = false
201-
ProgressUnknown(false, reentrantlocker, dt, 0, 0, false, tinit, tlast, printed, desc, color, spinner, output, 0, offset, enabled, showspeed, 1, 1, Int[])
163+
function ProgressUnknown(; spinner::Bool=false, kwargs...)
164+
CLEAR_IJULIA[] = clear_ijulia()
165+
core = ProgressCore(;kwargs...)
166+
new(false, spinner, 0, core)
167+
end
202168
end
203169

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

241207
# update progress display
242-
function updateProgress!(p::Progress; showvalues = (),
208+
function updateProgress!(p::Progress; showvalues = (),
243209
truncate_lines = false, valuecolor = :blue,
244-
offset::Integer = p.offset, keep = (offset == 0),
210+
offset::Integer = p.offset, keep = (offset == 0),
245211
desc::Union{Nothing,AbstractString} = nothing,
246212
ignore_predictor = false, color = p.color, max_steps = p.n)
247213
!p.enabled && return
@@ -326,9 +292,9 @@ function updateProgress!(p::Progress; showvalues = (),
326292
return nothing
327293
end
328294

329-
function updateProgress!(p::ProgressThresh; showvalues = (),
295+
function updateProgress!(p::ProgressThresh; showvalues = (),
330296
truncate_lines = false, valuecolor = :blue,
331-
offset::Integer = p.offset, keep = (offset == 0),
297+
offset::Integer = p.offset, keep = (offset == 0),
332298
desc = p.desc, ignore_predictor = false,
333299
color = p.color, thresh = p.thresh)
334300
!p.enabled && return
@@ -484,7 +450,7 @@ end
484450

485451
function lock_if_threading(f::Function, p::AbstractProgress)
486452
if is_threading(p)
487-
lock(p.reentrantlocker) do
453+
lock(p.lock) do
488454
f()
489455
end
490456
else
@@ -549,8 +515,8 @@ the message printed and its color.
549515
550516
See also `finish!`.
551517
"""
552-
function cancel(p::AbstractProgress, msg::AbstractString = "Aborted before all tasks were completed";
553-
color = :red, showvalues = (), truncate_lines = false,
518+
function cancel(p::AbstractProgress, msg::AbstractString = "Aborted before all tasks were completed";
519+
color = :red, showvalues = (), truncate_lines = false,
554520
valuecolor = :blue, offset = p.offset, keep = (offset == 0))
555521
lock_if_threading(p) do
556522
p.offset = offset
@@ -863,13 +829,13 @@ end
863829
864830
@showprogress [desc="Computing..."] pmap(x->x^2, 1:50)
865831
```
866-
displays progress in performing a computation. You may optionally
867-
supply a custom message to be printed that specifies the computation
832+
displays progress in performing a computation. You may optionally
833+
supply a custom message to be printed that specifies the computation
868834
being performed or other options.
869835
870-
`@showprogress` works for loops, comprehensions, and `map`-like
836+
`@showprogress` works for loops, comprehensions, and `map`-like
871837
functions. These `map`-like functions rely on `ncalls` being defined
872-
and can be checked with `methods(ProgressMeter.ncalls)`. New ones can
838+
and can be checked with `methods(ProgressMeter.ncalls)`. New ones can
873839
be added by defining `ProgressMeter.ncalls(::typeof(mapfun), args...) = ...`.
874840
875841
`@showprogress` is thread-safe and will work with `@distributed` loops
@@ -891,7 +857,7 @@ function showprogress(args...)
891857
throw(ArgumentError("Final argument to @showprogress must be a for loop, comprehension, or a map-like function; got $expr"))
892858
end
893859

894-
if expr.head == :call && expr.args[1] == :|>
860+
if expr.head == :call && expr.args[1] == :|>
895861
# e.g. map(x->x^2) |> sum
896862
expr.args[2] = showprogress(progressargs..., expr.args[2])
897863
return expr
@@ -908,7 +874,7 @@ function showprogress(args...)
908874
elseif expr.head == :macrocall
909875
macroname = expr.args[1]
910876

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

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

994-
if loopassign.head === :filter
960+
if loopassign.head === :filter
995961
# e.g. [x for x=1:10, y=1:10 if x>y]
996-
# y will be wrapped in ProgressWrapper
962+
# y will be wrapped in ProgressWrapper
997963
for i in 1:length(loopassign.args)-1
998964
loopassign.args[i] = esc(loopassign.args[i])
999965
end
@@ -1109,7 +1075,7 @@ to define the length of the `Progress` in `@showprogress` and `progress_map`.
11091075
Internally uses one of `ncalls_map`, `ncalls_broadcast(!)` or `ncalls_reduce` depending
11101076
on the type of `mapfun`.
11111077
1112-
Support for additional functions can be added by defining
1078+
Support for additional functions can be added by defining
11131079
`ProgressMeter.ncalls(::typeof(mapfun), ::Function, args...)`.
11141080
"""
11151081
ncalls(::typeof(map), ::Function, args...) = ncalls_map(args...)

0 commit comments

Comments
 (0)