blob: fdee4c3970f6ed122adb29617e7244bd414cba23 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.jmeter.util;
import org.apache.jmeter.samplers.SampleResult;
/**
* Class to calculate various items that don't require all previous results to be saved:
* <ul>
* <li>mean = average</li>
* <li>standard deviation</li>
* <li>minimum</li>
* <li>maximum</li>
* </ul>
*/
public class Calculator {
private double sum = 0;
private double sumOfSquares = 0;
private double mean = 0;
private double deviation = 0;
private int count = 0;
private long bytes = 0;
private long maximum = Long.MIN_VALUE;
private long minimum = Long.MAX_VALUE;
private int errors = 0;
private final String label;
public Calculator() {
this("");
}
public Calculator(String label) {
this.label = label;
}
public void clear() {
maximum = Long.MIN_VALUE;
minimum = Long.MAX_VALUE;
sum = 0;
sumOfSquares = 0;
mean = 0;
deviation = 0;
count = 0;
}
/**
* Add the value for (possibly multiple) samples.
* Updates the count, sum, min, max, sumOfSqaures, mean and deviation.
*
* @param newValue the total value for all the samples.
* @param sampleCount number of samples included in the value
*/
private void addValue(long newValue, int sampleCount) {
count += sampleCount;
double currentVal = newValue;
sum += currentVal;
if (sampleCount > 1){
minimum=Math.min(newValue/sampleCount, minimum);
maximum=Math.max(newValue/sampleCount, maximum);
// For n values in an aggregate sample the average value = (val/n)
// So need to add n * (val/n) * (val/n) = val * val / n
sumOfSquares += (currentVal * currentVal) / (sampleCount);
} else { // no point dividing by 1
minimum=Math.min(newValue, minimum);
maximum=Math.max(newValue, maximum);
sumOfSquares += currentVal * currentVal;
}
// Calculate each time, as likely to be called for each add
mean = sum / count;
deviation = Math.sqrt((sumOfSquares / count) - (mean * mean));
}
public void addBytes(long newValue) {
bytes += newValue;
}
private long startTime = 0;
private long elapsedTime = 0;
/**
* Add details for a sample result, which may consist of multiple samples.
* Updates the number of bytes read, error count, startTime and elapsedTime
* @param res the sample result; might represent multiple values
*/
public void addSample(SampleResult res) {
addBytes(res.getBytes());
addValue(res.getTime(),res.getSampleCount());
errors+=res.getErrorCount(); // account for multiple samples
if (startTime == 0){ // not yet intialised
startTime=res.getStartTime();
} else {
startTime = Math.min(startTime, res.getStartTime());
}
elapsedTime = Math.max(elapsedTime, res.getEndTime()-startTime);
}
public long getTotalBytes() {
return bytes;
}
public double getMean() {
return mean;
}
public Number getMeanAsNumber() {
return Long.valueOf((long) mean);
}
public double getStandardDeviation() {
return deviation;
}
public long getMin() {
return minimum;
}
public long getMax() {
return maximum;
}
public int getCount() {
return count;
}
public String getLabel() {
return label;
}
/**
* Returns the raw double value of the percentage of samples with errors
* that were recorded. (Between 0.0 and 1.0)
*
* @return the raw double value of the percentage of samples with errors
* that were recorded.
*/
public double getErrorPercentage() {
double rval = 0.0;
if (count == 0) {
return (rval);
}
rval = (double) errors / (double) count;
return (rval);
}
/**
* Returns the throughput associated to this sampler in requests per second.
* May be slightly skewed because it takes the timestamps of the first and
* last samples as the total time passed, and the test may actually have
* started before that start time and ended after that end time.
*
* @return throughput associated to this sampler in requests per second
*/
public double getRate() {
if (elapsedTime == 0) {
return 0.0;
}
return ((double) count / (double) elapsedTime ) * 1000;
}
/**
* calculates the average page size, which means divide the bytes by number
* of samples.
*
* @return average page size in bytes
*/
public double getAvgPageBytes() {
if (count > 0 && bytes > 0) {
return (double) bytes / count;
}
return 0.0;
}
/**
* Throughput in bytes / second
*
* @return throughput in bytes/second
*/
public double getBytesPerSecond() {
if (elapsedTime > 0) {
return bytes / ((double) elapsedTime / 1000); // 1000 = millisecs/sec
}
return 0.0;
}
/**
* Throughput in kilobytes / second
*
* @return Throughput in kilobytes / second
*/
public double getKBPerSecond() {
return getBytesPerSecond() / 1024; // 1024=bytes per kb
}
}