Class: Log::ProgressBar

Inherits:
Object
  • Object
show all
Defined in:
lib/rbbt/util/log/progress.rb,
lib/rbbt/util/log/progress/util.rb,
lib/rbbt/util/log/progress/report.rb

Constant Summary collapse

BAR_MUTEX =
Mutex.new
BARS =
[]
REMOVE =
[]
SILENCED =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max = nil, options = {}) ⇒ ProgressBar

Returns a new instance of ProgressBar.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/rbbt/util/log/progress.rb', line 8

def initialize(max = nil, options = {})
  options = Misc.add_defaults options, :depth => 0, :num_reports => 100, :desc => "Progress", :io => STDERR, :severity => Log.severity
  depth, num_reports, desc, io, severity, file, bytes = Misc.process_options options, :depth, :num_reports, :desc, :io, :severity, :file, :bytes

  @max = max
  @ticks = 0
  @frequency = 2
  @last_time = nil
  @last_count = nil
  @last_percent = nil
  @depth = depth
  @desc = desc.nil? ? "Progress" : desc.gsub(/\n/,' ')
  @file = file
  @bytes = bytes
end

Instance Attribute Details

#bytesObject

Returns the value of attribute bytes.



7
8
9
# File 'lib/rbbt/util/log/progress.rb', line 7

def bytes
  @bytes
end

#depthObject

Returns the value of attribute depth.



7
8
9
# File 'lib/rbbt/util/log/progress.rb', line 7

def depth
  @depth
end

#descObject

Returns the value of attribute desc.



7
8
9
# File 'lib/rbbt/util/log/progress.rb', line 7

def desc
  @desc
end

#fileObject

Returns the value of attribute file.



7
8
9
# File 'lib/rbbt/util/log/progress.rb', line 7

def file
  @file
end

#frequencyObject

Returns the value of attribute frequency.



7
8
9
# File 'lib/rbbt/util/log/progress.rb', line 7

def frequency
  @frequency
end

#historyObject

Returns the value of attribute history.



20
21
22
# File 'lib/rbbt/util/log/progress/report.rb', line 20

def history
  @history
end

#maxObject

Returns the value of attribute max.



7
8
9
# File 'lib/rbbt/util/log/progress.rb', line 7

def max
  @max
end

#max_historyObject

Returns the value of attribute max_history.



20
21
22
# File 'lib/rbbt/util/log/progress/report.rb', line 20

def max_history
  @max_history
end

#mean_maxObject

Returns the value of attribute mean_max.



20
21
22
# File 'lib/rbbt/util/log/progress/report.rb', line 20

def mean_max
  @mean_max
end

#ticksObject

Returns the value of attribute ticks.



7
8
9
# File 'lib/rbbt/util/log/progress.rb', line 7

def ticks
  @ticks
end

Class Method Details

.add_offsetObject



8
9
10
11
12
# File 'lib/rbbt/util/log/progress/util.rb', line 8

def self.add_offset
  @@offset = offset + 1
  @@offset = 0 if @@offset < 0
  @@offset
end

.cleanup_barsObject



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rbbt/util/log/progress/util.rb', line 37

def self.cleanup_bars
  BAR_MUTEX.synchronize do
    REMOVE.each do |bar|
      index = BARS.index bar
      if index
        BARS.delete_at index
        BARS.each_with_index do |bar,i|
          bar.depth = i
        end
      end
      index = SILENCED.index bar
      if index
        SILENCED.delete_at index
        SILENCED.each_with_index do |bar,i|
          bar.depth = i
        end
      end
    end
    REMOVE.clear
    BARS.length
  end
end

.new_bar(max, options = {}) ⇒ Object



27
28
29
30
31
32
33
34
35
# File 'lib/rbbt/util/log/progress/util.rb', line 27

def self.new_bar(max, options = {})
  cleanup_bars
  BAR_MUTEX.synchronize do
    #Log::LAST.replace "new_bar" if Log::LAST == "progress"
    options = Misc.add_defaults options, :depth => BARS.length + Log::ProgressBar.offset
    BARS << (bar = ProgressBar.new(max, options))
    bar
  end
end

.offsetObject



21
22
23
24
25
# File 'lib/rbbt/util/log/progress/util.rb', line 21

def self.offset
  @@offset ||= 0
  @@offset = 0 if @@offset < 0
  @@offset
end

.remove_bar(bar, error = false) ⇒ Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/rbbt/util/log/progress/util.rb', line 60

def self.remove_bar(bar, error = false)
  if error
    bar.error if bar.respond_to? :error
  else
    bar.done if bar.respond_to? :done
  end
  BAR_MUTEX.synchronize do
    REMOVE << bar
  end
end

.remove_offsetObject



14
15
16
17
18
# File 'lib/rbbt/util/log/progress/util.rb', line 14

def self.remove_offset
  @@offset = offset - 1
  @@offset = 0 if @@offset < 0
  @@offset
end

.with_bar(max, options = {}) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rbbt/util/log/progress/util.rb', line 71

def self.with_bar(max, options = {})
  bar = new_bar(max, options)
  begin
    yield bar
    keep = false
  rescue KeepBar
    keep = true
  ensure
    remove_bar(bar) if bar
  end
end

Instance Method Details

#done(io = STDERR) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/rbbt/util/log/progress/report.rb', line 160

def done(io = STDERR)
  done_msg = Log.color(:magenta, desc) << " " << Log.color(:green, "done")
  if @start
    ellapsed = (Time.now - @start).to_i
  else
    ellapsed = 0
  end
  ellapsed = [ellapsed/3600, ellapsed/60 % 60, ellapsed % 60].map{|t| "%02i" % t }.join(':')
  done_msg << " " << Log.color(:blue, (@ticks).to_s) << " #{bytes ? 'bytes' : 'items'} in " << Log.color(:green, ellapsed)
  @last_count = 0
  @last_time = @start
  done_msg << " (" << thr_msg << ")"
  print(io, up_lines(@depth) << done_msg << down_lines(@depth)) 
  Open.rm @file if @file and Open.exists? @file
end

#down_lines(depth) ⇒ Object



7
8
9
# File 'lib/rbbt/util/log/progress/report.rb', line 7

def down_lines(depth)
  "\n\033[#{depth + 2}E"
end

#error(io = STDERR) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/rbbt/util/log/progress/report.rb', line 176

def error(io = STDERR)
  done_msg = Log.color(:magenta, desc) << " " << Log.color(:red, "error")
  if @start
    ellapsed = (Time.now - @start).to_i
  else
    ellapsed = 0
  end
  ellapsed = [ellapsed/3600, ellapsed/60 % 60, ellapsed % 60].map{|t| "%02i" % t }.join(':')
  done_msg << " " << Log.color(:blue, (@ticks).to_s) << " in " << Log.color(:green, ellapsed)
  @last_count = 0
  @last_time = @start
  done_msg << " (" << thr_msg << ")"
  print(io, up_lines(@depth) << done_msg << down_lines(@depth)) 
  Open.rm @file if @file and Open.exists? @file
end

#eta_msgObject



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rbbt/util/log/progress/report.rb', line 81

def eta_msg
  percent = self.percent
  time = Time.now

  indicator = ""
  10.times{|i|
    if i < percent / 10 then
      indicator << Log.color(:yellow, ".")
    else
      indicator << " "
    end
  }

  indicator << " #{Log.color(:blue, percent.to_s << "%")}"

  used = time - @start
  if @mean_max and @mean_max > 0 and @mean > 0
    eta =  (@max - @ticks) / @mean
  else
    eta =  (@max - @ticks) / (@ticks/used)
  end

  used = Misc.format_seconds(used) 
  eta = [eta/3600, eta/60 % 60, eta % 60].map{|t| "%02i" % t }.join(':')

  #indicator << " #{Log.color :yellow, used} used #{Log.color :yellow, eta} left - #{Log.color :yellow, ticks.to_s} of #{Log.color :yellow, @max.to_s} #{bytes ? 'bytes' : 'items'}"
  indicator << " #{Log.color :yellow, eta} => #{Log.color :yellow, used} - #{Log.color :yellow, ticks.to_s} of #{Log.color :yellow, @max.to_s} #{bytes ? 'bytes' : 'items'}"

  indicator
end

#initObject



30
31
32
33
34
# File 'lib/rbbt/util/log/progress.rb', line 30

def init
  @start = @last_time = Time.now
  @last_count = 0
  report
end

#percentObject



24
25
26
27
28
# File 'lib/rbbt/util/log/progress.rb', line 24

def percent
  return 0 if @ticks == 0
  return 100 if @max == 0
  (@ticks * 100) / @max
end


11
12
13
14
15
16
17
18
# File 'lib/rbbt/util/log/progress/report.rb', line 11

def print(io, str)
  return if ENV["RBBT_NO_PROGRESS"] == "true"
  LOG_MUTEX.synchronize do
    STDERR.print str
    Log.logfile.puts str unless Log.logfile.nil?
    Log::LAST.replace "progress"
  end
end

#report(io = STDERR) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rbbt/util/log/progress/report.rb', line 136

def report(io = STDERR)
  if Log::LAST != "progress"
    length = Log::ProgressBar.cleanup_bars
    bars = BARS
    print(io, Log.color(:yellow, "...Progress\n"))
    bars.sort_by{|b| b.depth }.reverse.each do |bar|
      if SILENCED.include? bar
        print(io, Log.color(:yellow ,bar.report_msg) << "\n") 
      else
        print(io, "\n") 
      end
    end
  else
    bars = BARS
  end

  print(io, up_lines(bars.length) << Log.color(:yellow, "...Progress\n") << down_lines(bars.length)) 
  print(io, up_lines(@depth) << report_msg << down_lines(@depth)) 
  @last_time = Time.now
  @last_count = ticks
  @last_percent = percent if max and max > 0
  save if @file
end

#report_msgObject



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rbbt/util/log/progress/report.rb', line 112

def report_msg
  str = Log.color :magenta, desc
  if @ticks == 0
    if @max
      return str << " " << Log.color(:yellow, "waiting on #{@max} #{bytes ? 'bytes' : 'items'}") 
    else
      return str << " " << Log.color(:yellow, "waiting - PID: #{Process.pid}") 
    end
  end
  str << " " << thr_msg
  if max
    str << Log.color(:blue, " -- ") << eta_msg
  else
    str << Log.color(:blue, " -- ") << ticks.to_s << " #{bytes ? 'bytes' : 'items'}"
  end
  str
end

#saveObject



130
131
132
133
134
# File 'lib/rbbt/util/log/progress/report.rb', line 130

def save
  info = {:start => @start, :last_time => @last_time, :last_count => @last_count, :last_percent => @last_percent, :desc => @desc, :ticks => @ticks, :max => @max, :mean => @mean}
  info.delete_if{|k,v| v.nil?}
  Open.write(@file, info.to_yaml)
end

#thrObject



21
22
23
24
25
26
27
28
29
# File 'lib/rbbt/util/log/progress/report.rb', line 21

def thr
  count = @ticks - @last_count
  if @last_time.nil?
    seconds = 0.001
  else
    seconds = Time.now - @last_time
  end
  thr = count / seconds
end

#thr_msgObject



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rbbt/util/log/progress/report.rb', line 31

def thr_msg
  thr = self.thr
  if @history.nil?
    @history ||= [thr]
  else
    @history << thr
    max_history ||= case 
                  when @ticks > 20
                    count = @ticks - @last_count
                    if @max
                      times = @max / count
                      num = times / 20
                      num = 2 if num < 2
                    else
                      num = 10
                    end
                    count * num
                  else
                    20
                  end
    max_history = 30 if max_history > 30
    @history.shift if @history.length > max_history
  end

  @mean_max ||= 0
  if @history.length > 3

    w_mean = 0
    total_w = 0
    @history.each_with_index do |v,i|
      c = i ** 10
      w_mean += v * c
      total_w += c
    end
    mean = @mean = w_mean.to_f / total_w

    @mean_max = mean if mean > @mean_max
  end

  if mean.nil? or mean.to_i > 1
    str = "#{ Log.color :blue, thr.to_i.to_s } per sec."
    str << " #{ Log.color :yellow, mean.to_i.to_s } avg. #{Log.color :yellow, @mean_max.to_i.to_s} max." if @mean_max > 0
  else
    str = "#{ Log.color :blue, (1/thr).ceil.to_s } secs each"
    str << " #{ Log.color :yellow, (1/mean).ceil.to_s } avg. #{Log.color :yellow, (1/@mean_max).ceil.to_s} min." if @mean_max > 0
  end

  str
end

#tick(step = 1) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/rbbt/util/log/progress.rb', line 36

def tick(step = 1)
  return if ENV["RBBT_NO_PROGRESS"] == "true"
  @ticks += step

  begin
    time = Time.now
    if @last_time.nil?
      @last_time = time
      @last_count = @ticks
      @start = time
      return
    end

    diff = time - @last_time
    report and return if diff > @frequency
    return unless max and max > 0

    percent = self.percent
    if @last_percent.nil?
      @last_percent = percent
      return
    end
    report and return if percent > @last_percent and diff > 0.3
  rescue Exception
    Log.warn "Exception during report: " << $!.message
    Log.exception $!
  end
end

#up_lines(depth) ⇒ Object



3
4
5
# File 'lib/rbbt/util/log/progress/report.rb', line 3

def up_lines(depth)
  "\033[#{depth + 1}F\033[2K"
end