blob: f9da229a4777afd6c0db785538956e9b35c3ebe1 [file] [log] [blame] [raw]
/***************************************************************************
status.cpp
-------------------
begin : Sat Sep 29 2001
copyright : (C) 2001 - 2007 by Roland Riegel
email : feedback@roland-riegel.de
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "status.h"
#include "window.h"
#include "options.h"
using namespace std;
Status::Status()
{
m_min = m_max = m_cur = m_total = 0;
m_averagesmoothness = 0;
}
Status::~Status()
{
}
// new traffic measurement has been made => update statistics
void Status::update(unsigned long new_value, long long new_total)
{
m_cur = new_value;
minMax(m_cur); // calculate new min/max traffic values
updateAverage(m_cur); // calculate new average
/*
* set new total transfered data
* the following is a workaround for the value limitations of the
* unsigned int variable used in the kernel to produce
* the /proc/net/dev file
* (the total bytes value reaches 4GB and then switches to 0)
*/
if(new_total >= UINT_MAX)
m_total = new_total;
else if(new_total < (m_total % UINT_MAX))
m_total = ((m_total / UINT_MAX) + 1) * UINT_MAX + new_total;
else
m_total = (m_total / UINT_MAX) * UINT_MAX + new_total;
}
// print statistics
void Status::print(Window& window, int x, int y, status_format traff_format, status_format data_format)
{
unsigned long value;
char fText[100] = "";
string unit_string;
float unit_factor;
// print current traffic
window.setXY(x, y);
getUnit(traff_format, m_cur, unit_string, unit_factor);
sprintf(fText, "Curr: %.2f %s/s\n", m_cur / unit_factor, unit_string.c_str());
window.print(fText);
// print average traffic
window.setX(x);
value = calcAverage();
getUnit(traff_format, value, unit_string, unit_factor);
sprintf(fText, "Avg: %.2f %s/s\n", value / unit_factor, unit_string.c_str());
window.print(fText);
// print min traffic since nload start
window.setX(x);
getUnit(traff_format, m_min, unit_string, unit_factor);
sprintf(fText, "Min: %.2f %s/s\n", m_min / unit_factor, unit_string.c_str());
window.print(fText);
// print max traffic since nload start
window.setX(x);
getUnit(traff_format, m_max, unit_string, unit_factor);
sprintf(fText, "Max: %.2f %s/s\n", m_max / unit_factor, unit_string.c_str());
window.print(fText);
// print total traffic since last system reboot
window.setX(x);
getUnit(data_format, m_total, unit_string, unit_factor);
sprintf(fText, "Ttl: %.2f %s\n", m_total / unit_factor, unit_string.c_str());
window.print(fText);
}
// reset all displayed values to zero
void Status::resetTrafficData()
{
m_cur = m_min = m_max = m_total = 0;
m_average_values.clear();
}
// determine the matching unit string, e.g. "kBit" for status_format::kilobit, and
// the matching conversion factor between Byte and e.g. status_format::kilobit
void Status::getUnit(status_format format, long long value, string& description, float& factor)
{
factor = (float) 1 / (format % 2 == 0 ? 8 : 1);
description = format % 2 == 0 ? "Bit" : "Byte";
switch(format)
{
case human_readable_bit:
case human_readable_byte:
factor *= 1024 * 1024 * 1024;
for(int i = 3; i >= 0; i--)
{
if(value * (format % 2 == 0 ? 8 : 1) >= factor)
switch(i)
{
case 3:
description = 'G' + description;
return;
case 2:
description = 'M' + description;
return;
case 1:
description = 'k' + description;
return;
default:
return;
}
factor /= 1024;
}
return;
case bit:
case byte:
return;
case kilobit:
case kilobyte:
factor *= 1024;
description = 'k' + description;
return;
case megabit:
case megabyte:
factor *= 1024 * 1024;
description = 'M' + description;
return;
case gigabit:
case gigabyte:
factor *= 1024 * 1024 * 1024;
description = 'G' + description;
return;
default: // should never be executed
return;
}
}
// calculate min and max traffic values
void Status::minMax(unsigned long new_value)
{
// if this is the first time call, set min/max to current value
if(m_min == 0 && m_max == 0)
{
m_min = new_value;
m_max = new_value;
return;
}
m_min = new_value < m_min ? new_value : m_min;
m_max = new_value > m_max ? new_value : m_max;
}
// set the "reaction time" to the current traffic situation of the average values
void Status::setAverageSmoothness(OptionInt* new_averagesmoothness)
{
m_averagesmoothness = new_averagesmoothness;
}
// put new value into average calculation
void Status::updateAverage(unsigned long new_value)
{
/*
* average calculation is not very good at the moment as it is dependent
* from the display refresh interval.
* could need some help here.
*/
m_average_values.push_front(new_value);
// limit value count dependent of the average smoothness
// ranges between 1 * 45 and 9 * 45 single values
while(m_average_values.size() > (unsigned int) *m_averagesmoothness * 45)
{
m_average_values.pop_back();
}
}
// calculate current average
unsigned long Status::calcAverage()
{
if(m_average_values.size() == 0) return 0;
unsigned long sum = 0;
for(list<unsigned long>::const_iterator i = m_average_values.begin(); i != m_average_values.end(); i++)
{
sum += (*i);
}
return sum / m_average_values.size();
}
int Status::averageSmoothness()
{
int avg_smooth = m_averagesmoothness ? (int) *m_averagesmoothness : STANDARD_AVERAGE_SMOOTHNESS;
return avg_smooth > 9 ? 9 : (avg_smooth < 1 ? 1 : avg_smooth);
}