/*******************************************************************************
* Copyright 2013-2015 alladin-IT GmbH
*
* Licensed 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 at.alladin.rmbt.client;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import at.alladin.rmbt.client.helper.TestStatus;
import at.alladin.rmbt.client.v2.task.service.TestMeasurement;
import at.alladin.rmbt.client.v2.task.service.TestMeasurement.TrafficDirection;
public class TotalTestResult extends TestResult
{
public double speed_upload;
public double speed_download;
public long bytes_download;
public long nsec_download;
public long bytes_upload;
public long nsec_upload;
public long totalDownBytes;
public long totalUpBytes;
private Map<TestStatus, TestMeasurement> measurementMap;
private TestMeasurement totalTrafficMeasurement;
public void setMeasurementMap(Map<TestStatus, TestMeasurement> trafficMap) {
this.measurementMap = trafficMap;
}
public Map<TestStatus, TestMeasurement> getMeasurementMap() {
return measurementMap;
}
public void setTotalTrafficMeasurement(TestMeasurement measurement) {
this.totalTrafficMeasurement = measurement;
}
public long getTotalTrafficMeasurement(TrafficDirection dir) {
if (totalTrafficMeasurement != null) {
switch (dir) {
case RX:
return totalTrafficMeasurement.getRxBytes();
case TX:
return totalTrafficMeasurement.getTxBytes();
case TOTAL:
return totalTrafficMeasurement.getTxBytes() + totalTrafficMeasurement.getRxBytes();
}
}
return 0;
}
public long getTrafficByTestPart(TestStatus testStatusPart, TrafficDirection dir) {
if (measurementMap != null) {
TestMeasurement measurement = measurementMap.get(testStatusPart);
if (measurement != null) {
switch (dir) {
case RX:
return measurement.getRxBytes();
case TX:
return measurement.getTxBytes();
case TOTAL:
return measurement.getTxBytes() + measurement.getRxBytes();
}
}
}
return 0;
}
public TestMeasurement getTestMeasurementByTestPart(TestStatus testStatusPart) {
if (measurementMap != null) {
return measurementMap.get(testStatusPart);
}
return null;
}
public double getDownloadSpeedBitPerSec()
{
return getSpeedBitPerSec(bytes_download, nsec_download);
}
public double getUploadSpeedBitPerSec()
{
return getSpeedBitPerSec(bytes_upload, nsec_upload);
}
public void calculateDownload(final long[][] bytes, final long[][] nsecs)
{
calculate(bytes, nsecs, false);
}
public void calculateUpload(final long[][] bytes, final long[][] nsecs)
{
calculate(bytes, nsecs, true);
}
public static TotalTestResult calculateAndGet(final Map<Integer, List<SpeedItem>> speedMap) {
final int threads = speedMap.keySet().size();
long[][] allBytes = null;
long[][] allNsecs = null;
int threadCounter = 0;
for (Entry<Integer, List<SpeedItem>> e : speedMap.entrySet()) {
final List<SpeedItem> speedList = e.getValue();
if (allBytes == null) {
allBytes = new long[threads][speedList.size()];
allNsecs = new long[threads][speedList.size()];
}
for (int i = 0; i < speedList.size(); i++) {
allBytes[threadCounter][i] = speedList.get(i).bytes;
allNsecs[threadCounter][i] = speedList.get(i).time;
}
threadCounter++;
}
return TotalTestResult.calculateAndGet(allBytes, allNsecs, false);
}
public static TotalTestResult calculateAndGet(final long[][] allBytes, final long[][] allNsecs, final boolean upload) {
final TotalTestResult totalResult = new TotalTestResult();
totalResult.calculate(allBytes, allNsecs, upload);
return totalResult;
}
private void calculate(final long[][] allBytes, final long[][] allNsecs, final boolean upload)
{
if (allBytes.length != allNsecs.length)
throw new IllegalArgumentException();
final int numThreads = allBytes.length;
long targetTime = Long.MAX_VALUE;
for (int i = 0; i < numThreads; i++)
{
final long[] nsecs = allNsecs[i];
if (nsecs != null && nsecs.length > 0)
if (nsecs[nsecs.length - 1] < targetTime)
targetTime = nsecs[nsecs.length - 1];
}
long totalBytes = 0;
for (int i = 0; i < numThreads; i++)
{
final long[] bytes = allBytes[i];
final long[] nsecs = allNsecs[i];
if (bytes != null && nsecs != null && bytes.length > 0)
{
if (bytes.length != nsecs.length)
throw new IllegalArgumentException();
int targetIdx = bytes.length;
for (int j = 0; j < bytes.length; j++)
if (nsecs[j] > targetTime)
{
targetIdx = j;
break;
}
final long calcBytes;
if (targetIdx == bytes.length)
// nsec[max] == targetTime
calcBytes = bytes[bytes.length - 1];
else
{
final long bytes1 = targetIdx == 0 ? 0 : bytes[targetIdx - 1];
final long bytes2 = bytes[targetIdx];
final long bytesDiff = bytes2 - bytes1;
final long nsec1 = targetIdx == 0 ? 0 : nsecs[targetIdx - 1];
final long nsec2 = nsecs[targetIdx];
final long nsecDiff = nsec2 - nsec1;
final long nsecCompensation = targetTime - nsec1;
final double factor = (double) nsecCompensation / (double) nsecDiff;
long compensation = Math.round(bytesDiff * factor);
if (compensation < 0)
compensation = 0;
calcBytes = bytes1 + compensation;
}
totalBytes += calcBytes;
}
}
if (upload)
{
bytes_upload = totalBytes;
nsec_upload = targetTime;
speed_upload = getUploadSpeedBitPerSec() / 1e3;
}
else
{
bytes_download = totalBytes;
nsec_download = targetTime;
speed_download = getDownloadSpeedBitPerSec() / 1e3;
}
}
}