Back to index

openldap  2.4.31
meter.c
Go to the documentation of this file.
00001 /* meter.c - lutil_meter meters */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright (c) 2009 by Matthew Backes, Symas Corp.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was initially developed by Matthew Backes for inclusion
00018  * in OpenLDAP software.
00019  */
00020 
00021 #include "portable.h"
00022 #include "lutil_meter.h"
00023 
00024 #include <ac/assert.h>
00025 #include <ac/string.h>
00026 
00027 int
00028 lutil_time_string (
00029        char *dest,
00030        int duration,
00031        int max_terms)
00032 {
00033        static const int time_div[] = {31556952,
00034                                    604800,
00035                                    86400,
00036                                    3600,
00037                                    60,
00038                                    1,
00039                                    0};
00040        const int * time_divp = time_div;
00041        static const char * time_name_ch = "ywdhms";
00042        const char * time_name_chp = time_name_ch;
00043        int term_count = 0;
00044        char *buf = dest;
00045        int time_quot;
00046        
00047        assert ( max_terms >= 2 ); /* room for "none" message */
00048 
00049        if ( duration < 0 ) {
00050               *dest = '\0';
00051               return 1;
00052        }
00053        if ( duration == 0 ) {
00054               strcpy( dest, "none" );
00055               return 0;
00056        }
00057        while ( term_count < max_terms && duration > 0 ) {
00058               if (duration > *time_divp) {
00059                      time_quot = duration / *time_divp;
00060                      duration %= *time_divp;
00061                      if (time_quot > 99) {
00062                             return 1;
00063                      } else {
00064                             *(buf++) = time_quot / 10 + '0';
00065                             *(buf++) = time_quot % 10 + '0';
00066                             *(buf++) = *time_name_chp;
00067                             ++term_count;
00068                      }
00069               }
00070               if ( *(++time_divp) == 0) duration = 0;
00071               ++time_name_chp;
00072        }
00073        *buf = '\0';
00074        return 0;
00075 }
00076 
00077 int
00078 lutil_get_now (double *now)
00079 {
00080 #ifdef HAVE_GETTIMEOFDAY
00081        struct timeval tv;
00082 
00083        assert( now );
00084        gettimeofday( &tv, NULL );
00085        *now = ((double) tv.tv_sec) + (((double) tv.tv_usec) / 1000000.0);
00086        return 0;
00087 #else
00088        time_t tm;
00089 
00090        assert( now );
00091        time( &tm );
00092        *now = (double) tm;
00093        return 0;
00094 #endif
00095 }
00096 
00097 int
00098 lutil_meter_open (
00099        lutil_meter_t *meter,
00100        const lutil_meter_display_t *display, 
00101        const lutil_meter_estimator_t *estimator,
00102        unsigned long goal_value)
00103 {
00104        int rc;
00105 
00106        assert( meter != NULL );
00107        assert( display != NULL );
00108        assert( estimator != NULL );
00109 
00110        if (goal_value < 1) return -1;
00111 
00112        memset( (void*) meter, 0, sizeof( lutil_meter_t ));
00113        meter->display = display;
00114        meter->estimator = estimator;
00115        lutil_get_now( &meter->start_time );
00116        meter->last_update = meter->start_time;
00117        meter->goal_value = goal_value;
00118        meter->last_position = 0;
00119 
00120        rc = meter->display->display_open( &meter->display_data );
00121        if( rc != 0 ) return rc;
00122        
00123        rc = meter->estimator->estimator_open( &meter->estimator_data );
00124        if( rc != 0 ) {
00125               meter->display->display_close( &meter->display_data );
00126               return rc;
00127        }
00128        
00129        return 0;
00130 }
00131 
00132 int
00133 lutil_meter_update (
00134        lutil_meter_t *meter,
00135        unsigned long position,
00136        int force)
00137 {
00138        static const double display_rate = 0.5;
00139        double frac, cycle_length, speed, now;
00140        time_t remaining_time, elapsed;
00141        int rc;
00142 
00143        assert( meter != NULL );
00144 
00145        lutil_get_now( &now );
00146 
00147        if ( !force && now - meter->last_update < display_rate ) return 0;
00148 
00149        frac = ((double)position) / ((double) meter->goal_value);
00150        elapsed = now - meter->start_time;
00151        if (frac <= 0.0) return 0;
00152        if (frac >= 1.0) {
00153               rc = meter->display->display_update(
00154                      &meter->display_data,
00155                      1.0,
00156                      0,
00157                      (time_t) elapsed,
00158                      ((double)position) / elapsed);
00159        } else {
00160               rc = meter->estimator->estimator_update( 
00161                      &meter->estimator_data, 
00162                      meter->start_time,
00163                      frac,
00164                      &remaining_time );
00165               if ( rc == 0 ) {
00166                      cycle_length = now - meter->last_update;
00167                      speed = cycle_length > 0.0 ?
00168                             ((double)(position - meter->last_position)) 
00169                             / cycle_length :
00170                             0.0;
00171                      rc = meter->display->display_update(
00172                             &meter->display_data,
00173                             frac,
00174                             remaining_time,
00175                             (time_t) elapsed,
00176                             speed);
00177                      if ( rc == 0 ) {
00178                             meter->last_update = now;
00179                             meter->last_position = position;
00180                      }
00181               }
00182        }
00183 
00184        return rc;
00185 }
00186 
00187 int
00188 lutil_meter_close (lutil_meter_t *meter)
00189 {
00190        meter->estimator->estimator_close( &meter->estimator_data );
00191        meter->display->display_close( &meter->display_data );
00192 
00193        return 0;
00194 }
00195 
00196 /* Default display and estimator */
00197 typedef struct {
00198        int buffer_length;
00199        char * buffer;
00200        int need_eol;
00201        int phase;
00202        FILE *output;
00203 } text_display_state_t;
00204 
00205 static int
00206 text_open (void ** display_datap)
00207 {
00208        static const int default_buffer_length = 81;
00209        text_display_state_t *data;
00210 
00211        assert( display_datap != NULL );
00212        data = calloc( 1, sizeof( text_display_state_t ));
00213        assert( data != NULL );
00214        data->buffer_length = default_buffer_length;
00215        data->buffer = calloc( 1, default_buffer_length );
00216        assert( data->buffer != NULL );
00217        data->output = stderr;
00218        *display_datap = data;
00219        return 0;
00220 }
00221 
00222 static int
00223 text_update ( 
00224        void **display_datap,
00225        double frac,
00226        time_t remaining_time,
00227        time_t elapsed,
00228        double byte_rate)
00229 {
00230        text_display_state_t *data;
00231        char *buf, *buf_end;
00232 
00233        assert( display_datap != NULL );
00234        assert( *display_datap != NULL );
00235        data = (text_display_state_t*) *display_datap;
00236 
00237        if ( data->output == NULL ) return 1;
00238 
00239        buf = data->buffer;
00240        buf_end = buf + data->buffer_length - 1;
00241 
00242 /* |#################### 100.00% eta  1d19h elapsed 23w 7d23h15m12s spd nnnn.n M/s */
00243 
00244        {
00245               /* spinner */
00246               static const int phase_mod = 8;
00247               static const char phase_char[] = "_.-*\"*-.";
00248               *buf++ = phase_char[data->phase % phase_mod];
00249               data->phase++;
00250        }
00251 
00252        {
00253               /* bar */
00254               static const int bar_length = 20;
00255               static const double bar_lengthd = 20.0;
00256               static const char fill_char = '#';
00257               static const char blank_char = ' ';
00258               char *bar_end = buf + bar_length;
00259               char *bar_pos = frac < 0.0 ? 
00260                      buf :
00261                      frac < 1.0 ?
00262                      buf + (int) (bar_lengthd * frac) :
00263                      bar_end;
00264 
00265               assert( (buf_end - buf) > bar_length );
00266               while ( buf < bar_end ) {
00267                      *buf = buf < bar_pos ?
00268                             fill_char : blank_char;
00269                      ++buf;
00270               }
00271        }
00272 
00273        {
00274               /* percent */
00275               (void) snprintf( buf, buf_end-buf, "%7.2f%%", 100.0*frac );
00276               buf += 8;
00277        }
00278 
00279        {
00280               /* eta and elapsed */
00281               char time_buffer[19];
00282               int rc;
00283               rc = lutil_time_string( time_buffer, remaining_time, 2);
00284               if (rc == 0)
00285                      snprintf( buf, buf_end-buf, " eta %6s", time_buffer );
00286               buf += 5+6;
00287               rc = lutil_time_string( time_buffer, elapsed, 5);
00288               if (rc == 0)
00289                      snprintf( buf, buf_end-buf, " elapsed %15s", 
00290                               time_buffer );
00291               buf += 9+15;
00292        }
00293 
00294        {
00295               /* speed */
00296               static const char prefixes[] = " kMGTPEZY";
00297               const char *prefix_chp = prefixes;
00298 
00299               while (*prefix_chp && byte_rate >= 1024.0) {
00300                      byte_rate /= 1024.0;
00301                      ++prefix_chp;
00302               }
00303               if ( byte_rate >= 1024.0 ) {
00304                      snprintf( buf, buf_end-buf, " fast!" );
00305                      buf += 6;
00306               } else {
00307                      snprintf( buf, buf_end-buf, " spd %5.1f %c/s",
00308                               byte_rate,
00309                               *prefix_chp);
00310                      buf += 5+6+4;
00311               }
00312        }
00313 
00314        (void) fprintf( data->output,
00315                      "\r%-79s", 
00316                      data->buffer );
00317        data->need_eol = 1;
00318        return 0;
00319 }
00320 
00321 static int
00322 text_close (void ** display_datap)
00323 {
00324        text_display_state_t *data;
00325 
00326        if (display_datap) {
00327               if (*display_datap) {
00328                      data = (text_display_state_t*) *display_datap;
00329                      if (data->output && data->need_eol) 
00330                             fputs ("\n", data->output);
00331                      if (data->buffer)
00332                             free( data->buffer );
00333                      free( data );
00334               }
00335               *display_datap = NULL;
00336        }
00337        return 0;
00338 }
00339 
00340 static int
00341 null_open_close (void **datap)
00342 {
00343        assert( datap );
00344        *datap = NULL;
00345        return 0;
00346 }
00347 
00348 static int
00349 linear_update (
00350        void **estimator_datap, 
00351        double start, 
00352        double frac, 
00353        time_t *remaining)
00354 {
00355        double now;
00356        double elapsed;
00357        
00358        assert( estimator_datap != NULL );
00359        assert( *estimator_datap == NULL );
00360        assert( start > 0.0 );
00361        assert( frac >= 0.0 );
00362        assert( frac <= 1.0 );
00363        assert( remaining != NULL );
00364        lutil_get_now( &now );
00365 
00366        elapsed = now-start;
00367        assert( elapsed >= 0.0 );
00368 
00369        if ( frac == 0.0 ) {
00370               return 1;
00371        } else if ( frac >= 1.0 ) {
00372               *remaining = 0;
00373               return 0;
00374        } else {
00375               *remaining = (time_t) (elapsed/frac-elapsed+0.5);
00376               return 0;
00377        }
00378 }
00379 
00380 const lutil_meter_display_t lutil_meter_text_display = {
00381        text_open, text_update, text_close
00382 };
00383 
00384 const lutil_meter_estimator_t lutil_meter_linear_estimator = {
00385        null_open_close, linear_update, null_open_close
00386 };