![JAR search and dependency download from the Maven repository](/logo.png)
src.it.unimi.dsi.big.mg4j.util.ProgressMeter Maven / Gradle / Ivy
Show all versions of mg4j-big Show documentation
package it.unimi.dsi.big.mg4j.util;
import it.unimi.dsi.Util;
import java.io.PrintStream;
/*
* MG4J: Managing Gigabytes for Java (big)
*
* Copyright (C) 2003-2011 Sebastiano Vigna
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see .
*
*/
/** Tunable progress meter.
*
* This class provides a simple way to display progress information about long-lasting activities. It also
* provides some time measurement.
*
*
To use this class, you first create a new meter (possibly specifying a {@link java.io.PrintStream} to
* receive the {@linkplain #out output}). The output of the meter depends on the quantum (how many calls to {@link #update()}
* cause a dot to be printed) and the items name (the name that will be used to denote counted
* items). These can be changed at any time with the suitable setters.
*
*
To measure the progress of an activity, you call {@link #start()} at the beginning, which will
* display the quantum. Then, each time you want to mark progress, you call {@link #update()}. When
* the activity is over, you call {@link #stop()}. At that point, the method {@link #toString()} returns
* information about the internal state of the meter (elapsed time, number of items per second) that
* can be printed or otherwise processed. If {@link #update()} has never been called, you will just
* get the elapsed time.
*
*
Additionally, by setting the {@linkplain #expectedUpdates(long) expected amount of updates} you
* can get some estimations on the completion time.
*
*
After you finished a run of the meter, you can change its attributes and call {@link #start()} again
* to measure another activity.
*
*
A typical call sequence to a progress meter is as follows:
*
* ProgressMeter pm = new ProgressMeter(10, "pumpkins");
* pm.start("Smashing pumpkins...");
* ... activity on pumpkins that calls update() on each pumpkin ...
* pm.done();
*
*
* A more flexible behaviour can be obtained at the end of the
* process by calling {@link #stop()}:
*
* ProgressMeter pm = new ProgressMeter(10, "pumpkins");
* pm.start("Smashing pumpkins...");
* ... activity on pumpkins that calls update() on each pumpkin ...
* pm.stop( " really done!" );
* System.err.println( pm );
*
*
* Note that the output stream of the meter is available via the public field {@link #out}: this
* makes it possible to pass around a meter and print additional information on the same stream of the meter.
*
* @author Sebastiano Vigna
* @since 0.6
* @deprecated Use a {@link it.unimi.dsi.logging.ProgressLogger} instead.
*/
@Deprecated
public final class ProgressMeter {
/** The time at the last call to {@link #start()}. */
private long start;
/** The time at the last call to {@link #stop()}. */
private long stop;
/** The number of calls to {@link #update()} since the last {@link #start()}. */
private long count;
/** The number of calls to {@link #update()} at the last intermediate speed print. */
private long lastCount;
/** The number of expected calls to {@link #update()} (used to compute the percentages, ignored if negative). */
private long expectedUpdates;
/** The time at the last intermediate speed print. */
private long last;
/** The quantum (number of calls to generate a dot). */
private int quantum;
/** The name of several counted items. */
private String itemsName;
/** Have we already shown the quantum? */
private boolean shownQuantum;
/** The output print stream. It can be used to print information on the same stream used by this progress meter. */
public final java.io.PrintStream out;
/** Creates a new progress meter with a quantum equal to one, printing on standard error. */
public ProgressMeter() {
this( 1 );
}
/** Creates a new progress meter with given quantum, printing on standard error.
*
* @param quantum the meter quantum.
*/
public ProgressMeter( final int quantum ) {
this( quantum, "items" );
}
/** Creates a new progress meter with given quantum, printing on standard error.
*
* @param quantum the meter quantum.
* @param itemsName a plural name denoting the counted items.
*/
public ProgressMeter( final int quantum, final String itemsName ) {
this( quantum, itemsName, System.err );
}
/** Creates a new progress meter with given quantum, printing on a given stream.
*
* @param out a stream that will receive the output of the meter.
* @param quantum the meter quantum.
* @param itemsName a plural name denoting the counted items.
*/
public ProgressMeter( final int quantum, final String itemsName, final PrintStream out ) {
this.out = out;
this.quantum = quantum;
this.itemsName = itemsName;
this.expectedUpdates = -1;
}
/** Updates the meter.
*
*
This call updates the meter internal count. If the count reaches a multiple of the quantum,
* a symbol will be printed.
*/
public void update() {
// This method is kept intentionally short so to make it more likely that it is inlined.
if ( ++count % quantum != 0 ) return;
updateInternal();
}
private void updateInternal() {
if ( ! shownQuantum && quantum != 1 ) {
shownQuantum = true;
final double itemsPerSec = count / ( millis() / 1000.0 );
final long millisToEnd = Math.round( ( expectedUpdates - count ) / ( itemsPerSec / 1000.0 ) );
out.print( "[. = " + Util.format( quantum ) + " " + itemsName + ", " + Util.format( itemsPerSec ) + " " + itemsName + "/s"
+ ( expectedUpdates > 0 ? "; " + Util.format( 100 * count / expectedUpdates ) + "% done, " + millis2hms( millisToEnd ) + " to end" : "" ) + "]" );
}
final long n = count / quantum;
if ( n % 100 == 0 ) {
final long deltaCount = count - lastCount;
final long deltaTime = System.currentTimeMillis() - last;
final double itemPerSec = ( deltaCount * 1000.0 ) / ( deltaTime + 1 );
final long millisToEnd = Math.round( ( expectedUpdates - count ) / ( itemPerSec / 1000.0 ) );
out.print( "[" + Util.format( count ) + " " + itemsName + ", " + millis2hms( millis() ) + ", " + Util.format( itemPerSec ) + " " + itemsName + "/s"
+ ( expectedUpdates > 0 ? "; " + Util.format( 100 * count / expectedUpdates ) + "% done, " + millis2hms( millisToEnd ) + " to end" : "" ) + "]" );
lastCount += deltaCount;
last += deltaTime;
return;
}
if ( n % 10 == 0 ) {
out.print( "+" );
return;
}
out.print( "." );
return;
}
/** Sets the quantum.
*
* @param quantum the new quantum.
*/
public void quantum( final int quantum ) {
this.quantum = quantum;
}
/** Returns the current quantum.
*
* @return the current quantum.
*/
public int quantum() {
return quantum;
}
/** Sets the count.
*
* @param count the new count.
*/
public void count( final long count ) {
this.count = count;
}
/** Returns the current count.
*
* @return the current count.
*/
public long count() {
return count;
}
/** Sets the expected number of updates.
*
* @param num the new number.
*/
public void expectedUpdates( final long num ) {
this.expectedUpdates = num;
}
/** Returns the expected number of updates.
*
* @return the current expected number of updates.
*/
public long expectedUpdates() {
return expectedUpdates;
}
/** Sets the items name.
*
* @param itemsName the new items name.
*/
public void itemsName( final String itemsName ) {
this.itemsName = itemsName;
}
/** Returns the current items name.
*
* @return the current items name.
*/
public String itemsName() {
return itemsName;
}
/** Starts the progress meter, displaying a message and resetting the count.
* @param message the message to display.
*/
public void start( final CharSequence message ) {
if ( message != null ) out.print( message );
start = last = System.currentTimeMillis();
lastCount = count = 0;
shownQuantum = false;
stop = -1;
}
/** Starts the progress meter, resetting the count.
*/
public void start() { start( null ); }
/** Stops the progress meter, displaying a message terminated by a newline.
*/
public void stop( final CharSequence message ) {
if ( stop != -1 ) return;
if ( message != null ) out.println( message );
stop = System.currentTimeMillis();
this.expectedUpdates = -1;
}
/** Stops the progress meter.
*/
public void stop() { stop( null ); }
/** Completes a run of this progress meter, printing " done." and printing this meter itself.
*/
public void done() {
stop( " done." );
out.println( this );
}
/** Returns the number of milliseconds between present time and the last call to {@link #start()}, if
* the meter is running, or between the last call to {@link #stop()} and the last call to {@link #start()}, if the
* meter is stopped.
*/
public long millis() {
if ( stop != -1 ) return stop - start;
else return System.currentTimeMillis() - start;
}
private String millis2hms( final long t ) {
if ( t < 1000 ) return t + "ms";
final long s = ( t / 1000 ) % 60;
final long m = ( ( t / 1000 ) / 60 ) % 60;
final long h = t / ( 3600 * 1000 );
if ( h == 0 && m == 0 ) return s + "s";
if ( h == 0 ) return m + "m " + s + "s";
return h + "h " + m + "m " + s + "s";
}
/** Converts the data stored in this meter to a string.
*
* @return the data in this meter in a printable form.
*/
public String toString() {
final long t = stop - start + 1 ;
if ( t <= 0 ) return "Illegal meter state";
return "Elapsed: " + millis2hms( t ) + ( count != 0 ? " [" + Util.format( count ) + " " + itemsName + ", " + Util.format( count / ( t / 1000.0 ) ) + " " + itemsName + "/s]" : "" );
}
}
// Local Variables:
// mode: jde
// tab-width: 4
// End: