/*
* This file is part of ELKI:
* Environment for Developing KDD-Applications Supported by Index-Structures
*
* Copyright (C) 2017
* ELKI Development Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.lmu.ifi.dbs.elki.logging.progress;
import java.util.concurrent.atomic.AtomicInteger;
import de.lmu.ifi.dbs.elki.logging.Logging;
/**
* Abstract base class for FiniteProgress objects.
*
* @author Erich Schubert
* @since 0.2
*/
public abstract class AbstractProgress implements Progress {
/**
* The number of items already processed at a time being.
*
* We use AtomicInteger to allow threaded use without synchronization.
*/
private AtomicInteger processed = new AtomicInteger(0);
/**
* The task name.
*/
private String task;
/**
* For logging rate control.
*/
private long lastLogged = 0;
/**
* Last logged value.
*/
private int lastValue = 0;
/**
* Last rate.
*/
protected double ratems = Double.NaN;
/**
* Default constructor.
*
* @param task Task name.
*/
public AbstractProgress(String task) {
super();
this.task = task;
}
/**
* Provides the name of the task.
*
* @return the name of the task
*/
public String getTask() {
return task;
}
/**
* Sets the number of items already processed at a time being.
*
* @param processed the number of items already processed at a time being
* @throws IllegalArgumentException if an invalid value was passed.
*/
protected void setProcessed(int processed) throws IllegalArgumentException {
this.processed.set(processed);
}
/**
* Sets the number of items already processed at a time being.
*
* @param processed the number of items already processed at a time being
* @param logger Logger to report to
* @throws IllegalArgumentException if an invalid value was passed.
*/
public void setProcessed(int processed, Logging logger) throws IllegalArgumentException {
setProcessed(processed);
if(testLoggingRate()) {
logger.progress(this);
}
}
/**
* Get the number of items already processed at a time being.
*
* @return number of processed items
*/
public int getProcessed() {
return processed.get();
}
/**
* Serialize a description into a String buffer.
*
* @param buf Buffer to serialize to
* @return Buffer the data was serialized to.
*/
@Override
public abstract StringBuilder appendToBuffer(StringBuilder buf);
/**
* Returns a String representation of the progress suitable as a message for
* printing to the command line interface.
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return appendToBuffer(new StringBuilder()).toString();
}
/**
* Increment the processed counter.
*
* @param logger Logger to report to.
*/
public void incrementProcessed(Logging logger) {
this.processed.incrementAndGet();
if(testLoggingRate()) {
logger.progress(this);
}
}
/**
* Logging rate control.
*
* @return true when logging is sensible
*/
protected boolean testLoggingRate() {
final int processed = getProcessed();
final long now = System.currentTimeMillis();
final long age = now - lastLogged;
if(!isComplete() && processed > 10 && age < 5E2) {
return false;
}
if(lastValue > 0) {
int increment = processed - lastValue;
double newrate = increment / (double) age;
ratems = ratems != ratems ? newrate : (.95 * ratems + .05 * newrate);
}
lastValue = processed;
lastLogged = now;
return true;
}
}