This is a inputstream that has some statistics built in like bytes/ps.
I think its a performance drain because of bigdecimal churn. The algoritm to estimate the velocity is also the most simple i could find. I did find more smooth algorithms, but i couldn’t get them to work, and i only could get the algorithm not to jump around by using bigdecimals.
I’m asking for help on this, since it combines both areas that i’m a absolute noob on, floating point errors, timers and concurrency.
Main class (bigdecimal churn)
package downloads;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
public class StatisticsInputStream extends InputStream {
private long totalBytesRead;
private long startTimeMillis;
private InputStream delegate;
private volatile long expectedSize;
private BigDecimal bytesPerMillisecond = BigDecimal.ZERO;
private BigDecimal thousand = BigDecimal.valueOf(1000);
private BigDecimal timeRemaing = BigDecimal.valueOf(-1);
public StatisticsInputStream(InputStream delegate, long expectedSize) {
super();
this.expectedSize = expectedSize;
this.delegate = delegate;
}
@Override
public long skip(long n) throws IOException {
return delegate.skip(n);
}
@Override
public synchronized void reset() throws IOException {
delegate.reset();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (startTimeMillis == 0) {
startTimeMillis = System.currentTimeMillis();
}
int read = delegate.read(b, off, len);
if (read != -1) {
updateMeasure(read);
}
return read;
}
@Override
public int read(byte[] b) throws IOException {
if (startTimeMillis == 0) {
startTimeMillis = System.currentTimeMillis();
}
int read = delegate.read(b);
if (read != -1) {
updateMeasure(read);
}
return read;
}
public int read() throws IOException {
if (startTimeMillis == 0) {
startTimeMillis = System.currentTimeMillis();
}
int byteRead = delegate.read();
if (byteRead != -1) {
updateMeasure(1);
}
return byteRead;
}
@Override
public boolean markSupported() {
return delegate.markSupported();
}
@Override
public synchronized void mark(int readlimit) {
delegate.mark(readlimit);
}
@Override
public void close() throws IOException {
delegate.close();
}
@Override
public int available() throws IOException {
return delegate.available();
}
protected void updateMeasure(int bytesRead) {
totalBytesRead += bytesRead;
long now = System.currentTimeMillis();
long delta_T = now - startTimeMillis;
//You'd think negative intervals couldn't happen. You'd be wrong.
if (delta_T <= 0) {
return;
}
//(time elapsed/dl'ed size)*size left
BigDecimal remainingBytes = BigDecimal.valueOf(getExpectedSize() - getBytesRead().longValue());
BigDecimal timeElapsed = BigDecimal.valueOf(delta_T);
BigDecimal bytes = BigDecimal.valueOf(totalBytesRead);
timeRemaing = timeElapsed.divide(bytes, 5, RoundingMode.HALF_UP).multiply(remainingBytes);
}
public BigDecimal getBytesPerSecond() {
return bytesPerMillisecond.multiply(thousand);
}
public BigInteger getBytesRead() {
return BigInteger.valueOf(totalBytesRead);
}
public BigDecimal getTimeRemaining() {
return timeRemaing;
}
/**
* @return the expectedSize
*/
public long getExpectedSize() {
return expectedSize;
}
/**
* @param expectedSize the expectedSize to set
*/
protected void setExpectedSize(long expectedSize) {
this.expectedSize = expectedSize;
}
}
