ARB
arb_progress.cxx
Go to the documentation of this file.
1 // ================================================================ //
2 // //
3 // File : arb_progress.cxx //
4 // Purpose : //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in November 2010 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // ================================================================ //
11 
12 #include <arb_progress.h>
13 #include <arb_handlers.h>
14 #include <algorithm>
15 
16 using namespace ArbProgress;
17 
18 // ----------------
19 // counter
20 
21 struct null_counter: public counter {
22  null_counter(nestable *owner) : counter(owner) {}
23 
24  void inc() OVERRIDE {}
26  void inc_by(SINT) OVERRIDE {}
27  void inc_to(SINT) OVERRIDE {}
29  void done() OVERRIDE {}
31  void auto_subtitles(const char *) OVERRIDE {}
32  bool has_auto_subtitles() OVERRIDE { return false; }
33  void child_updates_gauge(double ) OVERRIDE {
34  arb_assert(0); // wont
35  }
36 
37 #if defined(DUMP_PROGRESS)
38  void dump() const OVERRIDE {
39  fprintf(stderr, "null_counter\n");
40  }
41 #endif
42 
43  counter *clone(nestable *owner, SINT ) const OVERRIDE { return new null_counter(owner); }
44 };
45 
46 struct no_counter : public null_counter {
47  no_counter(nestable *owner) : null_counter(owner) {}
48  void inc() OVERRIDE {
49  arb_assert(0); // this is no_counter - so explicit inc() is prohibited!
50  }
51  void child_updates_gauge(double gauge) OVERRIDE { ownedBy->update_gauge(gauge); }
52 
53 #if defined(DUMP_PROGRESS)
54  void dump() const OVERRIDE {
55  fprintf(stderr, "no_counter (=wrapped null_counter)\n");
56  }
57 #endif
58 
60  arb_assert(0); // this method previously was not present => previously was cloned as null_counter!
61  return NULL;
62  }
63 };
64 
65 static void warn_and_dump_counter_or_calling_progress(const char *warnmsg, const counter *fallback);
66 
67 class concrete_counter FINAL_TYPE : public counter { // derived from a Noncopyable
68  SINT explicit_counter; // incremented by calls to inc() etc.
69  SINT implicit_counter; // incremented by child_done()
70  SINT maxcount; // == 0 -> does not really count (just a wrapper for child progresses)
71  double autoUpdateEvery;
72  double nextAutoUpdate;
73  char *auto_subtitle_prefix;
74  SINT last_auto_counter;
75 
76  SINT dispositive_counter() const { return std::max(implicit_counter, explicit_counter); }
77 
78  void init(SINT overallCount) {
79  arb_assert(overallCount>0);
80 
81  implicit_counter = 0;
82  explicit_counter = 0;
83  maxcount = overallCount;
84  autoUpdateEvery = overallCount/500.0; // update status approx. 500 times
85  nextAutoUpdate = 0;
86  }
87 
88  bool refresh_if_needed(double my_counter) { // (double needed when called for child_gauge)
89  arb_assert(my_counter>=0);
90  if (my_counter<nextAutoUpdate) return false;
91 
92  {
93  double gauge = my_counter/maxcount;
94  if (gauge>=1.05) { // 5% overflow detected
95  SINT new_maxcount = maxcount*1.2+0.5;
96 
97  char *warnmsg = GBS_global_string_copy("Warning: progress indicator overflow (%.1f%%/%li)\n"
98  "Estimation of time left is broken (assuming new maximum: +20%% -> %li)\n"
99  "Please report this problem to devel@arb-home.de\n"
100  "(please mention the full text shown in the progress bar window\n"
101  "AND include the newest session log (stored after quitting arb),\n"
102  "otherwise we'll not be able to fix this problem)",
103  (gauge-1)*100, maxcount, new_maxcount);
104 
106  free(warnmsg);
107 
108  arb_assert(0); // progress overflow
109 
110  maxcount = new_maxcount;
111  gauge = my_counter/maxcount;
112  }
113  ownedBy->update_gauge(gauge);
114  }
115 
116  if (auto_subtitle_prefix) {
117  SINT count = SINT(my_counter+1);
118  if (count>last_auto_counter && count <= maxcount) {
119  last_auto_counter = count; // important to set BEFORE calling set_text (which may recurse!)
120  const char *autosub = GBS_global_string("%s #%li/%li", auto_subtitle_prefix, count, maxcount);
121  ownedBy->set_text(LEVEL_SUBTITLE, autosub);
122  }
123  }
124  nextAutoUpdate += autoUpdateEvery;
125  return true;
126  }
127  void update_display_if_needed() {
128  refresh_if_needed(dispositive_counter());
129  }
130 
131  void force_update() OVERRIDE {
132  double oldNext = nextAutoUpdate;
133  nextAutoUpdate = 0;
134  update_display_if_needed();
135  nextAutoUpdate = oldNext;
136  }
137 
138  public:
139  concrete_counter(nestable *owner, SINT overall_count) :
140  counter(owner),
141  auto_subtitle_prefix(NULp),
142  last_auto_counter(0)
143  {
144  arb_assert(overall_count>0);
145  init(overall_count);
146  }
148  free(auto_subtitle_prefix);
149 #if defined(TEST_COUNTERS)
150  if (!ownedBy->accept_invalid_counters) {
151  arb_assert(implicit_counter || explicit_counter); // progress was never incremented
152 
153  arb_assert(implicit_counter <= maxcount); // overflow
154  arb_assert(explicit_counter <= maxcount); // overflow
155 
156  arb_assert(dispositive_counter() == maxcount); // progress did not finish
157  }
158 #endif
159  }
160 
161 #if defined(DUMP_PROGRESS)
162  void dump() const OVERRIDE {
163  fprintf(stderr,
164  "concrete_counter: explicit=%li, implicit=%li, maxcount=%li\n",
165  explicit_counter, implicit_counter, maxcount);
166  }
167 #endif
168 
169  void auto_subtitles(const char *prefix) OVERRIDE {
170  // activates use of a prefixed counter as subtitle: "prefix #some/all"
171  arb_assert(!auto_subtitle_prefix);
172  freedup(auto_subtitle_prefix, prefix);
173  force_update();
174  }
175  bool has_auto_subtitles() OVERRIDE { return auto_subtitle_prefix; }
176 
177  void inc() OVERRIDE { explicit_counter += 1; update_display_if_needed(); }
178  void implicit_inc() OVERRIDE { implicit_counter += 1; update_display_if_needed(); }
179 
180  void inc_to(SINT x) OVERRIDE {
181  explicit_counter = std::max(explicit_counter, x);
182  update_display_if_needed();
183  }
185  inc_to(std::min(maxcount, x));
186  }
187  void inc_by(SINT count) { inc_to(explicit_counter+count); }
188 
189  void done() OVERRIDE {
190  implicit_counter = explicit_counter = maxcount;
191  force_update();
192  }
193 
194  counter *clone(nestable *owner, SINT overall_count) const OVERRIDE {
195  return new concrete_counter(owner, overall_count);
196  }
197  void child_updates_gauge(double child_gauge) OVERRIDE {
198  refresh_if_needed(dispositive_counter()+child_gauge);
199  }
200 };
201 
202 // -----------------
203 // progress
204 
205 inline const char *spaced_weightable(const weightable& speed) {
206  if (!speed.is_weighted()) return "";
207  double phase1_weight = speed.get_adjusted_gauge(0.5);
208  return GBS_global_string(" (weighted: %.3f%%:%.3f%%)", phase1_weight*100, (1-phase1_weight)*100);
209 }
210 
211 static counter *make_counter(nestable *owner, SINT overall_count) {
212  if (overall_count) return new concrete_counter(owner, overall_count);
213  return new no_counter(owner);
214 }
215 
216 class child_progress FINAL_TYPE : public nestable { // derived from a Noncopyable
217  nestable *parent;
218  static child_progress *child_triggering_update;
219 
220 public:
221  child_progress(nestable *parent_, const char *title, SINT overall_count, const weightable& speed_) :
222  nestable(make_counter(this, overall_count), title, speed_),
223  parent(parent_)
224  {
225  set_text(LEVEL_TITLE, title);
226  DUMP_AS(GBS_global_string("child: %s%s", title ? title : "<untitled>", spaced_weightable(speed_)));
227  }
229  parent->child_terminated();
230  }
231 
232  SmartPtr<nestable> create_child_progress(const char *title, SINT overall_count, const weightable& speed_) OVERRIDE {
233  return new child_progress(this, title, overall_count, speed_);
234  }
235 
236 #if defined(DUMP_PROGRESS)
237  void dump() const OVERRIDE {
238  nestable::dump();
239  fprintf(stderr, "is child of\n");
240  parent->dump();
241  }
242 #endif
243 
244  void set_text(int level, const char *text) OVERRIDE { parent->child_sets_text(level+has_title-1, text); }
245 
246  void update_gauge(double gauge) OVERRIDE {
247  double adjusted_gauge = speed.get_adjusted_gauge(gauge);
248  if (!child_triggering_update) {
249  LocallyModify<child_progress*> storeUpdater(child_triggering_update, this);
250  parent->update_parent_gauge(adjusted_gauge);
251  }
252  else {
253  parent->update_parent_gauge(adjusted_gauge);
254  }
255  }
256 
257  static const child_progress *calling_child_progress() { return child_triggering_update; }
258 };
259 
260 child_progress *child_progress::child_triggering_update = NULp;
261 
262 static void warn_and_dump_counter_or_calling_progress(const char *warnmsg, const counter *fallback) {
263  GB_warning(warnmsg);
264  fprintf(stderr, "-------------------- warn_and_dump_counter_or_calling_progress [start]\n");
265  fputs(warnmsg, stderr);
266  fputc('\n', stderr);
267 #if defined(DUMP_PROGRESS)
268  const child_progress *updater = child_progress::calling_child_progress();
269  if (updater) {
270  updater->dump();
271  }
272  else { // assume this counter has been updated directly
273  fallback->dump();
274  }
275 #endif
276  fprintf(stderr, "-------------------- warn_and_dump_counter_or_calling_progress [end]\n");
277 }
278 
279 class initial_progress: public nestable {
280 
281 public:
282  initial_progress(const char *title, counter *counter_, const weightable& speed_)
283  : nestable(counter_, title, speed_)
284  {
285  DUMP_AS(GBS_global_string("initial: %s%s", title ? title : "<untitled>", spaced_weightable(speed_)));
286  if (!title) title = "..."; // use fake title (nestable got no title, so it will be replaced by child title)
287  impl->openstatus(title);
288  }
290  update_gauge(1.0); // due to numeric issues it often only counts up to 99.999%
291  impl->closestatus();
292  }
293 
294  SmartPtr<nestable> create_child_progress(const char *title, SINT overall_count, const weightable& speed_) OVERRIDE {
295  return new child_progress(this, title, overall_count, speed_);
296  }
297 
298  void set_text(int level, const char *text) OVERRIDE {
299  if (!text) return;
300  switch (level+has_title-1) {
301  case LEVEL_TITLE: impl->set_title(text); break;
302  case LEVEL_SUBTITLE:
303 #if defined(FORCE_WEIGHTED_ESTIMATION)
304  if (speed.is_weighted() || have_weighted_progress()) {
305  cntr->force_update(); // send most recent gauge
306  impl->set_subtitle("REQUEST_ESTIMATION"); // hack: force estimation
307  }
308 #endif
309  impl->set_subtitle(text);
310  break;
311  }
312  }
313 
314  void update_gauge(double gauge) OVERRIDE {
315  arb_assert(gauge>=0);
316  arb_assert(gauge<=1);
317 
318  double adjusted_gauge = speed.get_adjusted_gauge(gauge);
319  impl->set_gauge(adjusted_gauge);
320  }
321 };
322 
324  initial_selfRef_progress(const char *title, SINT overall_count, const weightable& speed_) :
325  initial_progress(title, make_counter(this, overall_count), speed_)
326  {}
327 };
328 
329 class null_progress: public nestable {
330  null_progress(counter *counter_to_clone, SINT overall_count, const weightable& speed_) : // only used by create_child_progress
331  nestable(counter_to_clone->clone(this, overall_count), false, speed_)
332  {
333  DUMP_AS("null_progress (cloned)");
334  }
335 public:
336  explicit null_progress() : // creates a suppressor
337  nestable(new null_counter(this), false, weightable())
338  {
339  DUMP_AS("null_progress (suppressor)");
340  }
341 
342  SmartPtr<nestable> create_child_progress(const char*, SINT overall_count, const weightable& speed_) OVERRIDE {
343  return new null_progress(cntr, overall_count, speed_);
344  }
345  void set_text(int,const char*) OVERRIDE {}
346  void update_gauge(double) OVERRIDE {
347  arb_assert(!speed.is_weighted()); // you can't weight nothing!
348  }
349 };
350 
351 // -------------------------
352 // progress factory
353 
355 arb_status_implementation *nestable::impl = NULp; // defines implementation to display status
356 
357 SmartPtr<nestable> nestable::create(const char *title, SINT overall_count, const double *phase1_fraction) {
358  weightable weighted = phase1_fraction ? weightable(*phase1_fraction) : weightable();
359  arb_assert(implicated(weighted.is_weighted(), overall_count == 2UL));
360 
361  if (recent) {
362  return recent->create_child_progress(title, overall_count, weighted);
363  }
365  return new initial_selfRef_progress(title, overall_count, weighted);
366 }
367 
369  return new null_progress;
370 }
371 
372 #if defined(FORCE_WEIGHTED_ESTIMATION)
375 }
376 #endif
377 
378 bool nestable::aborted() const {
379  if (impl) return impl->user_abort();
380  return false;
381 }
382 
383 
384 // --------------------------
385 // progress dumpers
386 
387 #if defined(DUMP_PROGRESS)
388 
389 // not inlined in header (otherwise they are missing while debugging)
390 
391 void nestable::dump() const {
392  fprintf(stderr, "progress %s\n", name);
393  fprintf(stderr, "counter: ");
394  cntr->dump();
395 }
396 
397 void arb_progress::dump() const {
398  fprintf(stderr, "--------------------\n");
399  used->dump();
400 }
401 
402 #endif
403 
#define arb_assert(cond)
Definition: arb_assert.h:245
initial_selfRef_progress(const char *title, SINT overall_count, const weightable &speed_)
bool is_weighted() const
Definition: arb_progress.h:62
void child_updates_gauge(double child_gauge) OVERRIDE
concrete_counter(nestable *owner, SINT overall_count)
void GB_warning(const char *message)
Definition: arb_msg.cxx:471
SmartPtr< nestable > create_child_progress(const char *title, SINT overall_count, const weightable &speed_) OVERRIDE
#define implicated(hypothesis, conclusion)
Definition: arb_assert.h:289
void inc_by(SINT) OVERRIDE
void implicit_inc() OVERRIDE
void implicit_inc() OVERRIDE
virtual SmartPtr< nestable > create_child_progress(const char *title, SINT overall_count, const weightable &speed_)=0
~child_progress() OVERRIDE
static SmartPtr< nestable > create(const char *title, SINT overall_count, const double *phase1_fraction)
initial_progress(const char *title, counter *counter_, const weightable &speed_)
void set_text(int, const char *) OVERRIDE
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:202
const char * title
Definition: readseq.c:22
void update_gauge(double gauge) OVERRIDE
bool this_or_recent_is_weighted() const
Definition: arb_progress.h:179
bool has_auto_subtitles() OVERRIDE
null_counter(nestable *owner)
no_counter(nestable *owner)
void done() OVERRIDE
virtual counter * clone(nestable *owner, SINT overall_count) const =0
const int LEVEL_SUBTITLE
Definition: arb_progress.h:117
arb_handlers * active_arb_handlers
static counter * make_counter(nestable *owner, SINT overall_count)
Generic smart pointer.
Definition: smartptr.h:149
static nestable * recent
Definition: arb_progress.h:135
static void warn_and_dump_counter_or_calling_progress(const char *warnmsg, const counter *fallback)
void child_updates_gauge(double gauge) OVERRIDE
void force_update() OVERRIDE
#define false
Definition: ureadseq.h:13
static bool have_weighted_progress()
~initial_progress() OVERRIDE
void inc_to_avoid_overflow(SINT x) OVERRIDE
fputc('\n', stderr)
void inc_to_avoid_overflow(SINT) OVERRIDE
counter * clone(nestable *owner, SINT overall_count) const OVERRIDE
counter * clone(nestable *, SINT) const OVERRIDE
void set_text(int level, const char *text) OVERRIDE
const char * spaced_weightable(const weightable &speed)
void done() OVERRIDE
SmartPtr< nestable > create_child_progress(const char *title, SINT overall_count, const weightable &speed_) OVERRIDE
void auto_subtitles(const char *) OVERRIDE
void inc() OVERRIDE
static arb_status_implementation * impl
Definition: arb_progress.h:136
fputs(TRACE_PREFIX, stderr)
void update_gauge(double) OVERRIDE
static SmartPtr< nestable > create_suppressor()
xml element
void inc_to(SINT) OVERRIDE
#define OVERRIDE
Definition: cxxforward.h:110
double get_adjusted_gauge(double linear_gauge) const
Definition: arb_progress.h:64
#define DUMP_AS(NAME)
Definition: arb_progress.h:126
~concrete_counter() OVERRIDE
static ARB_init_perl_interface init
Definition: ARB_ext.c:101
void set_text(int level, const char *text) OVERRIDE
void auto_subtitles(const char *prefix) OVERRIDE
#define NULp
Definition: cxxforward.h:114
bool has_auto_subtitles() OVERRIDE
void inc() OVERRIDE
virtual void dump() const
void child_updates_gauge(double) OVERRIDE
SmartPtr< nestable > create_child_progress(const char *, SINT overall_count, const weightable &speed_) OVERRIDE
arb_status_implementation status
Definition: arb_handlers.h:41
void inc_by(SINT count)
child_progress(nestable *parent_, const char *title, SINT overall_count, const weightable &speed_)
static const child_progress * calling_child_progress()
counter * clone(nestable *owner, SINT) const OVERRIDE
#define min(a, b)
Definition: f2c.h:153
void inc() OVERRIDE
virtual void dump() const =0
const int LEVEL_TITLE
Definition: arb_progress.h:116
void inc_to(SINT x) OVERRIDE
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:193
void update_gauge(double gauge) OVERRIDE
void dump() const
#define max(a, b)
Definition: f2c.h:154