source: trunk/CORE/arb_handlers.cxx

Last change on this file was 18959, checked in by westram, 3 years ago
File size: 8.1 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : arb_handlers.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_handlers.h>
13#include <arb_msg.h>
14#include "arb_misc.h"
15#include <smartptr.h>
16#include <unistd.h>
17#include <time.h>
18#include <arb_algo.h>
19
20// AISC_MKPT_PROMOTE:#ifndef ARB_CORE_H
21// AISC_MKPT_PROMOTE:#include <arb_core.h>
22// AISC_MKPT_PROMOTE:#endif
23
24static FILE *arberr = stderr;
25static FILE *arbout = stdout;
26
27static void to_arberr(const char *msg) {
28    fflush(arbout);
29    fprintf(arberr, "%s\n", msg);
30    fflush(arberr);
31}
32static void to_arbout(const char *msg) {
33    fprintf(arbout, "%s\n", msg);
34}
35
36// -------------------------
37//      ARB_arbout_status
38
39const int  WIDTH = 70;
40const char CHAR  = '.';
41
42const int MIN_SECONDS_PER_ROW = 10;   // otherwise decrease number of rows
43const int MAX_SECONDS_PER_ROW = 3*60; // otherwise increase number of rows
44
45const int DEFAULT_HEIGHT = 12; // 12 can be devided by 2, 3, 4, 6 (so subtitles tend to be at start of line)
46const int MAXHEIGHT      = 3*DEFAULT_HEIGHT;
47
48#if defined(DEBUG)
49// # define TRACE_BASIC_COUNTER
50#endif
51
52class BasicStatus : virtual Noncopyable {
53    int         openCount;
54    char       *subtitle;
55    const char *cursor;
56
57    int printed;
58    int height; // number of rows to print (gets decided while printing 1st row)
59
60    bool mayReconsiderHeight;   // true -> 'height' may change
61    int  printedAtHeightChange; // value of 'printed' at time when 'height' was reconsidered and changed
62
63    time_t start;
64
65    void reset() {
66        printed  = 0;
67        cursor   = NULp;
68        subtitle = NULp;
69
70        time(&start);
71
72        mayReconsiderHeight       = true;
73        printedAtHeightChange = 0;
74
75        height = DEFAULT_HEIGHT;
76    }
77
78public:
79    BasicStatus() : openCount(0) { reset(); }
80    ~BasicStatus() { if (openCount) close(); }
81
82    void open(const char *title) {
83        arb_assert(++openCount <= 1);
84        fprintf(arbout, "Progress: %s\n", title);
85        reset();
86    }
87    void close() {
88        freenull(subtitle);
89        fprintf(arbout, "[done]\n");
90        arb_assert(--openCount >= 0);
91        fflush(arbout);
92    }
93
94    int next_LF() const { return printed-printed%WIDTH+WIDTH; }
95
96    void set_subtitle(const char *stitle) {
97        arb_assert(openCount == 1);
98        if (!cursor) {
99#if defined(FORCE_WEIGHTED_ESTIMATION)
100            if (strcmp(stitle, "REQUEST_ESTIMATION") == 0) { // hack
101                return;
102            }
103#endif
104            freeset(subtitle, GBS_global_string_copy("{%s}", stitle));
105            cursor = subtitle;
106        }
107    }
108
109    static double estimate_overall_seconds(double seconds_passed, double gauge) {
110        return seconds_passed / gauge;
111    }
112
113    void set_gauge(double gauge) {
114        arb_assert(openCount == 1);
115
116        int wanted = int(gauge*WIDTH*height);
117        if (printed<wanted) {
118#if defined(TRACE_BASIC_COUNTER)
119            fprintf(arbout, "\nBasicStatus::set_gauge(gauge=%f) -> wanted=%i printed=%i; ", gauge, wanted, printed);
120#endif
121            while (printed<wanted) {
122                if (cursor && cursor[0]) {
123                    fputc(*cursor++, arbout);
124                }
125                else {
126                    cursor = NULp;
127                    fputc(CHAR, arbout);
128                }
129                int nextLF = next_LF();
130                printed++;
131                if (printed == nextLF) {
132                    mayReconsiderHeight = false;
133
134                    time_t now;
135                    time(&now);
136
137                    fprintf(arbout, " [%5.1f%%]", printed*100.0/(WIDTH*height));
138                    bool   done    = (printed == (WIDTH*height));
139                    double seconds = difftime(now, start);
140
141                    const char *whatshown = done ? "used" : "left";
142                    fprintf(arbout, " %s: ", whatshown);
143
144                    long show_sec = done ? seconds : long((estimate_overall_seconds(seconds, gauge)-seconds)+0.5);
145                    fputs(GBS_readable_timediff(show_sec), arbout);
146                    fputc('\n', arbout);
147
148                    nextLF = next_LF();
149                }
150                else if (mayReconsiderHeight) {
151                    if ((2*printed) > nextLF) {
152                        mayReconsiderHeight = false; // stop redeciding
153                    }
154                    else {
155                        time_t now;
156                        time(&now);
157
158                        double seconds         = difftime(now, start)+0.5;
159                        double overall_seconds = estimate_overall_seconds(seconds, gauge);
160
161                        int max_wanted_height = int(overall_seconds/MIN_SECONDS_PER_ROW+0.5);
162                        int min_wanted_height = int(overall_seconds/MAX_SECONDS_PER_ROW+0.5);
163
164                        arb_assert(min_wanted_height <= max_wanted_height);
165
166                        int old_height = height;
167
168                        height = force_in_range(min_wanted_height, DEFAULT_HEIGHT, max_wanted_height);
169                        height = force_in_range(1, height, MAXHEIGHT);
170
171                        if (old_height != height) {
172#if defined(TRACE_BASIC_COUNTER)
173                            fprintf(arbout, "redeciding height=%i printedAtHeightChange=%i printed=%i wanted=%i\n", height, printedAtHeightChange, printed, wanted);
174#endif
175                            printedAtHeightChange = std::max(printedAtHeightChange, printed);
176                            // now 'wanted' got wrong -> rerun this loop by recursion
177                            set_gauge(gauge);
178                            return;
179                        }
180                    }
181                }
182            }
183            fflush(arbout);
184#if defined(DEBUG)
185            // ARB_sleep(25, MS); // uncomment to see slow status
186#endif
187        }
188        else if (!mayReconsiderHeight && printed>printedAtHeightChange && wanted<printed) {
189            arb_assert(wanted>0);
190            int print_limit = (printed * 9) / 10;
191            if (wanted<print_limit) {
192                int print_again_from = (wanted * 8) / 10;
193                fprintf(arbout, "\n *** progress counter ran backwards *** (wanted=%i printed=%i print_limit=%i print_again_from=%i)\n", wanted, printed, print_limit, print_again_from);
194                printed              = print_again_from;
195
196                // rerun this loop by recursion:
197                set_gauge(gauge);
198                arb_assert(0); // progress went backwards. to find reason, uncomment TRACE_BASIC_COUNTER and run in debugger!
199                return;
200            }
201        }
202    }
203};
204
205static BasicStatus status;
206
207static void basic_openstatus(const char *title) { status.open(title); }
208static void basic_closestatus() { status.close(); }
209static void basic_set_title(const char */*title*/) { }
210static void basic_set_subtitle(const char *stitle) { status.set_subtitle(stitle); }
211static void basic_set_gauge(double gauge) {
212    arb_assert(gauge>=0);
213    status.set_gauge(gauge);
214}
215static bool basic_user_abort() { return false; }
216
217static arb_status_implementation ARB_arbout_status = {
218    AST_FORWARD,
219    basic_openstatus,   // openstatus
220    basic_closestatus,  // closestatus
221    basic_set_title,    // set_title
222    basic_set_subtitle, // set_subtitle
223    basic_set_gauge,    // set_gauge
224    basic_user_abort    // user_abort
225};
226
227static arb_handlers arbout_handlers = {
228    to_arberr,
229    to_arbout,
230    to_arbout,
231    ARB_arbout_status,
232};
233
234arb_handlers *active_arb_handlers = &arbout_handlers; // default-handlers
235
236void ARB_install_handlers(arb_handlers& handlers) { active_arb_handlers = &handlers; }
237
238void ARB_redirect_handlers_to(FILE *errStream, FILE *outStream) {
239    arberr = errStream;
240    arbout = outStream;
241}
Note: See TracBrowser for help on using the repository browser.