/*
* Copyright 2016 christopher.metter.
*
* 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 de.uniwuerzburg.info3.ofcprobe.vswitch.statistics;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import de.uniwuerzburg.info3.ofcprobe.util.Util;
import de.uniwuerzburg.info3.ofcprobe.vswitch.main.config.Config;
import org.openflow.protocol.OFMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The TimeStampLogger
* Loggs SystenTimeStamps of each OFPAcketOut and OFPacketIn -> Can be Used for IAT of two OF_PACKET_INs
* @author Christopher Metter(christopher.metter@informatik.uni-wuerzburg.de)
*
*/
public class TimeStampLogger implements IStatistics {
/**
* The Logger
*/
private static final Logger logger = LoggerFactory.getLogger(TimeStampLogger.class);
/**
* Is session Running
*/
private boolean sessionRunning;
/**
* the Dpid
*/
private String dpid;
/**
* The OutputFile
*/
private String file;
/**
* MilliSecondsPerSecond
*/
private static int milliSecondsPerSecond = 1000;
/**
* Incoming TimeStamps
*/
private List<Long> incomingStamps;
/**
* List of MeanIncomingTimeStamps per Seconds
*/
private List<Double> incomingMeanIATperIntervall;
/**
* Temp List of Incoming TimeStamps for mean List
*/
private List<Long> incomingTemp;
/**
* Time of Next Reset for incoming Means
*/
private Date nextIncomingReset;
/**
* List of Outgoiung TimeStamps
*/
private List<Long> outgoingStamps;
/**
* List of MeanOutogingTimeStamps per Seocnds
*/
private List<Double> outgoingMeanIATperIntervall;
/**
* Temp List of Outoging TimeStamps for MeanList
*/
private List<Long> outgoingTemp;
/**
* Time of Next Reset for outgoingMeans
*/
private Date nextOutgoingReset;
private Date startDate;
/**
* The Constructor
* @param config the Config
*/
public TimeStampLogger(Config config){
this.sessionRunning = false;
NumberFormat formatter = new DecimalFormat("#000");
this.dpid = formatter.format(config.getSwitchConfig().getDpid());
this.startDate = new Date();
/**
* TIMESTAMPS OF INCOMING PACKETS = OF_PACKET_OUT
*/
this.incomingStamps = new ArrayList<Long>();
int simulationTime = ((int) Math.floor(config.getSimTime() / 1000)) + 15;
ArrayList<Double> temp1 = new ArrayList<Double>();
Util.ensureSizeDouble(temp1, simulationTime);
this.incomingMeanIATperIntervall = temp1;
this.incomingTemp = new ArrayList<Long>();
this.nextIncomingReset = new Date(System.currentTimeMillis() + milliSecondsPerSecond);
/**
* TIMESTAMPS of OUTGOING PACKETS = OF_PACKET_IN
*/
this.outgoingStamps = new ArrayList<Long>();
ArrayList<Double> temp2 = new ArrayList<Double>();
Util.ensureSizeDouble(temp2, simulationTime);
this.outgoingMeanIATperIntervall = temp2;
this.outgoingTemp = new ArrayList<Long>();
this.nextOutgoingReset = new Date(System.currentTimeMillis() + milliSecondsPerSecond);
}
@Override
public void setReportFile(String file) {
this.file = file;
}
@Override
public void packetIn(OFMessage in) {
if (!this.sessionRunning) return;
switch(in.getType()) {
case PACKET_OUT:
Date now = new Date();
if (now.after(this.nextIncomingReset)){
Iterator<Long> iter = this.incomingTemp.iterator();
double iat_mean = 0.0;
while (iter.hasNext()) {
iat_mean += iter.next();
}
iat_mean = iat_mean / this.incomingTemp.size();
if (Double.isNaN(iat_mean)) {
iat_mean = 0;
}
int intervall = Util.getIntervall(this.startDate, now);
// Util.listSizeCheck(this.incomingMeanIATperIntervall, intervall);
this.incomingMeanIATperIntervall.add(intervall, iat_mean);
logger.trace("[Switch#{}]: New Incoming IAT Intervall Mean: {}", this.dpid, iat_mean);
this.incomingTemp.clear();
this.nextIncomingReset = new Date(this.nextIncomingReset.getTime() + milliSecondsPerSecond);
}
long value = lastValueGetter(false, now);
this.incomingTemp.add(value);
this.incomingStamps.add(now.getTime());
logger.trace("[Switch#{}]: New Incoming TimeStamp added: {}", this.dpid, now.getTime());
break;
default:
break;
}
}
@Override
public void packetOut(OFMessage out) {
if (!this.sessionRunning) return;
switch(out.getType()) {
case PACKET_IN:
Date now = new Date();
if (now.after(this.nextOutgoingReset)) {
Iterator<Long> iter = this.outgoingTemp.iterator();
double iat_mean = 0.0;
while (iter.hasNext()) {
iat_mean += iter.next();
}
iat_mean = iat_mean / this.outgoingTemp.size();
if (Double.isNaN(iat_mean)) {
iat_mean = 0;
}
int intervall = Util.getIntervall(this.startDate, now);
// Util.listSizeCheck(this.outgoingMeanIATperIntervall, intervall);
this.outgoingMeanIATperIntervall.add(intervall, iat_mean);
logger.trace("[Switch#{}]: New Outgoing IAT Intervall Mean: {}",this.dpid, iat_mean);
this.outgoingTemp.clear();
this.nextOutgoingReset = new Date(this.nextOutgoingReset.getTime() + milliSecondsPerSecond);
}
long value = lastValueGetter(true, now);
this.outgoingTemp.add(value);
this.outgoingStamps.add(now.getTime());
logger.trace("[Switch#{}]: New Outgoing TimeStamp added: {}", this.dpid, now.getTime());
break;
default:
break;
}
}
@Override
public void evaluate() {
synchronized (this.outgoingTemp) {
if (!this.outgoingTemp.isEmpty()) {
Iterator<Long> iter = this.outgoingTemp.iterator();
double iat_mean = 0.0;
while(iter.hasNext()) {
Long next = iter.next();
iat_mean += next;
}
iat_mean = iat_mean/this.outgoingTemp.size();
if (Double.isNaN(iat_mean)) {
iat_mean = 0;
}
this.outgoingMeanIATperIntervall.add(iat_mean);
this.outgoingTemp.clear();
}
if (!this.incomingTemp.isEmpty()) {
Iterator<Long> iter = this.incomingTemp.iterator();
double iat_mean = 0;
while(iter.hasNext()) {
Long next = iter.next();
iat_mean += next;
}
iat_mean = iat_mean/this.incomingTemp.size();
if (Double.isNaN(iat_mean)) {
iat_mean = 0;
}
this.incomingMeanIATperIntervall.add(iat_mean);
this.incomingTemp.clear();
}
double totalIncomingIatMean = 0.0;
Iterator<Double> incomingIter = this.incomingMeanIATperIntervall.iterator();
while (incomingIter.hasNext()) {
totalIncomingIatMean += incomingIter.next();
}
totalIncomingIatMean = totalIncomingIatMean / this.incomingMeanIATperIntervall.size();
if (Double.isNaN(totalIncomingIatMean)) {
totalIncomingIatMean = 0.0;
}
logger.info("[Switch#{}]: Total Incoming IAT Mean: {}", this.dpid, totalIncomingIatMean);
double totalOutgoingIatMean = 0.0;
Iterator<Double> outgoingIter = this.outgoingMeanIATperIntervall.iterator();
while (outgoingIter.hasNext()) {
totalOutgoingIatMean += outgoingIter.next();
}
totalOutgoingIatMean = totalOutgoingIatMean / this.outgoingMeanIATperIntervall.size();
if (Double.isNaN(totalOutgoingIatMean)) {
totalOutgoingIatMean = 0.0;
}
logger.info("[Switch#{}]: Total Outgoing IAT Mean: {}", this.dpid, totalOutgoingIatMean);
}
}
@Override
public void report() {
writeToFile();
}
@Override
public void start() {
this.sessionRunning = true;
this.startDate = new Date();
this.nextIncomingReset = new Date(System.currentTimeMillis() + milliSecondsPerSecond);
this.nextOutgoingReset = this.nextIncomingReset;
}
@Override
public void stop() {
if (this.sessionRunning) {
this.sessionRunning = false;
}
}
/**
* Write Results to File
*/
private void writeToFile() {
try {
File filou = new File(this.file);
if (!filou.getParentFile().exists()) {
filou.getParentFile().mkdirs();
}
PrintWriter out = new PrintWriter(this.file);
if (!this.outgoingMeanIATperIntervall.isEmpty()) {
Iterator<Double> outIATiter = this.outgoingMeanIATperIntervall.iterator();
while(outIATiter.hasNext()){
out.print(outIATiter.next());
out.print(";");
}
} else {
out.print("0;");
}
out.print("\n");
if (!this.incomingMeanIATperIntervall.isEmpty()) {
Iterator<Double> inIATiter = this.incomingMeanIATperIntervall.iterator();
while(inIATiter.hasNext()){
out.print(inIATiter.next());
out.print(";");
}
} else {
out.print("0;");
}
out.print("\n");
if (!this.outgoingStamps.isEmpty()) {
Iterator<Long> outIter = this.outgoingStamps.iterator();
while (outIter.hasNext()) {
out.print(outIter.next());
out.print(";");
}
} else {
out.print("0;");
}
out.print("\n");
if (!this.incomingStamps.isEmpty()) {
Iterator<Long> inIter = this.incomingStamps.iterator();
while(inIter.hasNext()) {
out.print(inIter.next());
out.print(";");
}
} else {
out.print("0;");
}
out.print("\n");
out.close();
} catch (FileNotFoundException e) {
logger.error("[Switch#{}]: {}", this.dpid, e);
}
}
/**
* Get Last Values
* @param outgoing flag if Outgoing or Incoming Value is searched
* @param now now Date
* @return long
*/
private long lastValueGetter(boolean outgoing, Date now){
if (outgoing) {//packetOut()
if (!this.outgoingStamps.isEmpty()) {
long value = now.getTime() - this.outgoingStamps.get(this.outgoingStamps.size() - 1);
return value;
} else {
return (long) 0;
}
} else { // packetIn()
if (!this.incomingStamps.isEmpty()) {
long value = now.getTime() - this.incomingStamps.get(this.incomingStamps.size() - 1);
return value;
} else {
return (long) 0;
}
}
}
}