1 /* meter.c - lutil_meter meters */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright (c) 2009 by Matthew Backes, Symas Corp.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was initially developed by Matthew Backes for inclusion
18 * in OpenLDAP software.
22 #include "lutil_meter.h"
24 #include <ac/assert.h>
25 #include <ac/string.h>
33 static const int time_div[] = {31556952,
40 const int * time_divp = time_div;
41 static const char * time_name_ch = "ywdhms";
42 const char * time_name_chp = time_name_ch;
47 assert ( max_terms >= 2 ); /* room for "none" message */
53 if ( duration == 0 ) {
54 strcpy( dest, "none" );
57 while ( term_count < max_terms && duration > 0 ) {
58 if (duration > *time_divp) {
59 time_quot = duration / *time_divp;
60 duration %= *time_divp;
64 *(buf++) = time_quot / 10 + '0';
65 *(buf++) = time_quot % 10 + '0';
66 *(buf++) = *time_name_chp;
70 if ( *(++time_divp) == 0) duration = 0;
78 lutil_get_now (double *now)
80 #ifdef HAVE_GETTIMEOFDAY
84 gettimeofday( &tv, NULL );
85 *now = ((double) tv.tv_sec) + (((double) tv.tv_usec) / 1000000.0);
100 const lutil_meter_display_t *display,
101 const lutil_meter_estimator_t *estimator,
102 unsigned long goal_value)
106 assert( meter != NULL );
107 assert( display != NULL );
108 assert( estimator != NULL );
110 if (goal_value < 1) return -1;
112 memset( (void*) meter, 0, sizeof( lutil_meter_t ));
113 meter->display = display;
114 meter->estimator = estimator;
115 lutil_get_now( &meter->start_time );
116 meter->last_update = meter->start_time;
117 meter->goal_value = goal_value;
118 meter->last_position = 0;
120 rc = meter->display->display_open( &meter->display_data );
121 if( rc != 0 ) return rc;
123 rc = meter->estimator->estimator_open( &meter->estimator_data );
125 meter->display->display_close( &meter->display_data );
134 lutil_meter_t *meter,
135 unsigned long position,
138 static const double display_rate = 0.5;
139 double frac, cycle_length, speed, now;
140 time_t remaining_time, elapsed;
143 assert( meter != NULL );
145 lutil_get_now( &now );
147 if ( !force && now - meter->last_update < display_rate ) return 0;
149 frac = ((double)position) / ((double) meter->goal_value);
150 elapsed = now - meter->start_time;
151 if (frac <= 0.0) return 0;
153 rc = meter->display->display_update(
154 &meter->display_data,
158 ((double)position) / elapsed);
160 rc = meter->estimator->estimator_update(
161 &meter->estimator_data,
166 cycle_length = now - meter->last_update;
167 speed = cycle_length > 0.0 ?
168 ((double)(position - meter->last_position))
171 rc = meter->display->display_update(
172 &meter->display_data,
178 meter->last_update = now;
179 meter->last_position = position;
188 lutil_meter_close (lutil_meter_t *meter)
190 meter->estimator->estimator_close( &meter->estimator_data );
191 meter->display->display_close( &meter->display_data );
196 /* Default display and estimator */
203 } text_display_state_t;
206 text_open (void ** display_datap)
208 static const int default_buffer_length = 81;
209 text_display_state_t *data;
211 assert( display_datap != NULL );
212 data = calloc( 1, sizeof( text_display_state_t ));
213 assert( data != NULL );
214 data->buffer_length = default_buffer_length;
215 data->buffer = calloc( 1, default_buffer_length );
216 assert( data->buffer != NULL );
217 data->output = stderr;
218 *display_datap = data;
224 void **display_datap,
226 time_t remaining_time,
230 text_display_state_t *data;
233 assert( display_datap != NULL );
234 assert( *display_datap != NULL );
235 data = (text_display_state_t*) *display_datap;
237 if ( data->output == NULL ) return 1;
240 buf_end = buf + data->buffer_length - 1;
242 /* |#################### 100.00% eta 1d19h elapsed 23w 7d23h15m12s spd nnnn.n M/s */
246 static const int phase_mod = 8;
247 static const char phase_char[] = "_.-*\"*-.";
248 *buf++ = phase_char[data->phase % phase_mod];
254 static const int bar_length = 20;
255 static const double bar_lengthd = 20.0;
256 static const char fill_char = '#';
257 static const char blank_char = ' ';
258 char *bar_end = buf + bar_length;
259 char *bar_pos = frac < 0.0 ?
262 buf + (int) (bar_lengthd * frac) :
265 assert( (buf_end - buf) > bar_length );
266 while ( buf < bar_end ) {
267 *buf = buf < bar_pos ?
268 fill_char : blank_char;
275 (void) snprintf( buf, buf_end-buf, "%7.2f%%", 100.0*frac );
280 /* eta and elapsed */
281 char time_buffer[19];
283 rc = lutil_time_string( time_buffer, remaining_time, 2);
285 snprintf( buf, buf_end-buf, " eta %6s", time_buffer );
287 rc = lutil_time_string( time_buffer, elapsed, 5);
289 snprintf( buf, buf_end-buf, " elapsed %15s",
296 static const char prefixes[] = " kMGTPEZY";
297 const char *prefix_chp = prefixes;
299 while (*prefix_chp && byte_rate >= 1024.0) {
303 if ( byte_rate >= 1024.0 ) {
304 snprintf( buf, buf_end-buf, " fast!" );
307 snprintf( buf, buf_end-buf, " spd %5.1f %c/s",
314 (void) fprintf( data->output,
322 text_close (void ** display_datap)
324 text_display_state_t *data;
327 if (*display_datap) {
328 data = (text_display_state_t*) *display_datap;
329 if (data->output && data->need_eol)
330 fputs ("\n", data->output);
332 free( data->buffer );
335 *display_datap = NULL;
341 null_open_close (void **datap)
350 void **estimator_datap,
358 assert( estimator_datap != NULL );
359 assert( *estimator_datap == NULL );
360 assert( start > 0.0 );
361 assert( frac >= 0.0 );
362 assert( frac <= 1.0 );
363 assert( remaining != NULL );
364 lutil_get_now( &now );
367 assert( elapsed >= 0.0 );
371 } else if ( frac >= 1.0 ) {
375 *remaining = (time_t) (elapsed/frac-elapsed+0.5);
380 const lutil_meter_display_t lutil_meter_text_display = {
381 text_open, text_update, text_close
384 const lutil_meter_estimator_t lutil_meter_linear_estimator = {
385 null_open_close, linear_update, null_open_close