summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Rettberg2017-02-24 12:33:55 +0100
committerSimon Rettberg2017-02-24 12:33:55 +0100
commitd4f10f9fe446da2aff65088e5236d6ffcdd034b5 (patch)
tree5d7467a6f67272064619c000a14800e706368ac6 /src
downloadspeedcheck-d4f10f9fe446da2aff65088e5236d6ffcdd034b5.tar.gz
speedcheck-d4f10f9fe446da2aff65088e5236d6ffcdd034b5.tar.xz
speedcheck-d4f10f9fe446da2aff65088e5236d6ffcdd034b5.zip
initial commit
Diffstat (limited to 'src')
-rw-r--r--src/copythread.cpp72
-rw-r--r--src/copythread.h26
-rw-r--r--src/datasource/cpuload.cpp55
-rw-r--r--src/datasource/cpuload.h22
-rw-r--r--src/datasource/idatasource.h16
-rw-r--r--src/datasource/networkspeed.cpp50
-rw-r--r--src/datasource/networkspeed.h24
-rw-r--r--src/graphwidget.cpp95
-rw-r--r--src/graphwidget.h33
-rw-r--r--src/main.cpp16
-rw-r--r--src/speedcheck.cpp81
-rw-r--r--src/speedcheck.h35
-rw-r--r--src/types.h6
-rw-r--r--src/ui/speedcheck.ui107
14 files changed, 638 insertions, 0 deletions
diff --git a/src/copythread.cpp b/src/copythread.cpp
new file mode 100644
index 0000000..1f9ec2f
--- /dev/null
+++ b/src/copythread.cpp
@@ -0,0 +1,72 @@
+#include "copythread.h"
+#include <QFile>
+#include <QElapsedTimer>
+#include <QCoreApplication>
+#include <QDebug>
+
+// 1M read size
+#define BUFFER_SIZE (1000000)
+// 20 seconds for each test
+#define TEST_LENGTH (60000)
+
+CopyThread::CopyThread(QFile *file, QObject *parent)
+ : QThread(parent),
+ _doStop(false)
+{
+ _file = file;
+}
+
+CopyThread::~CopyThread()
+{
+ delete _file;
+}
+
+void CopyThread::stop()
+{
+ _doStop = true;
+}
+
+void CopyThread::run()
+{
+ qDebug() << "Entering run method";
+ char *buffer = new char[BUFFER_SIZE];
+ QElapsedTimer timer;
+ qint64 ret;
+ qint64 seqSum = 0, rndSum = 0;
+ qint64 seqTime, rndTime = -1;
+
+ // Sequential read
+ emit logMessage(trUtf8("Starting sequential read test"));
+ timer.start();
+ do {
+ ret = _file->read(buffer, BUFFER_SIZE);
+ seqSum += ret;
+ if (ret == 0) {
+ _file->seek(0);
+ }
+ } while (!_doStop && ret >= 0 && timer.elapsed() < TEST_LENGTH);
+ seqTime = timer.elapsed();
+
+ // Random read
+ qsrand((uint)QCoreApplication::applicationPid());
+ const qint64 size = _file->size() - BUFFER_SIZE;
+ if (size > 0) {
+ emit logMessage(trUtf8("Starting random read test"));
+ timer.restart();
+ do {
+ _file->seek(((qint64)qrand() ^ ((qint64)qrand() << 15)) % size);
+ ret = _file->read(buffer, BUFFER_SIZE);
+ rndSum += ret;
+ } while (!_doStop && ret > 0 && timer.elapsed() < TEST_LENGTH);
+ rndTime = timer.elapsed();
+ }
+
+ // All done
+ const qint64 seqSpeed = seqSum / (seqTime * 1024 + 1);
+ const qint64 rndSpeed = rndSum / (rndTime * 1024 + 1);
+ emit logMessage(trUtf8("Seq: %1MiB/s, Random: %2MiB/s - [%3s / %4s]")
+ .arg(QString::number(seqSpeed), QString::number(rndSpeed),
+ QString::number(seqTime / 1000), QString::number(rndTime / 1000)));
+ delete[] buffer;
+ _file->close();
+}
diff --git a/src/copythread.h b/src/copythread.h
new file mode 100644
index 0000000..428c7fa
--- /dev/null
+++ b/src/copythread.h
@@ -0,0 +1,26 @@
+#ifndef COPYTHREAD_H_
+#define COPYTHREAD_H_
+
+#include <QThread>
+
+class QFile;
+
+class CopyThread : public QThread {
+ Q_OBJECT
+public:
+ CopyThread(QFile *file, QObject *parent = NULL);
+ virtual ~CopyThread();
+ void stop();
+
+protected:
+ virtual void run();
+
+private:
+ QFile *_file;
+ volatile bool _doStop;
+
+signals:
+ void logMessage(QString message);
+};
+
+#endif /* COPYTHREAD_H_ */
diff --git a/src/datasource/cpuload.cpp b/src/datasource/cpuload.cpp
new file mode 100644
index 0000000..48831f3
--- /dev/null
+++ b/src/datasource/cpuload.cpp
@@ -0,0 +1,55 @@
+#include "cpuload.h"
+#include <QStringList>
+
+CpuLoad::CpuLoad() :
+ _lastLoad(0),
+ _lastTotal(0),
+ _file("/proc/stat")
+{
+ // TODO Auto-generated constructor stub
+
+}
+
+CpuLoad::~CpuLoad() {
+ // TODO Auto-generated destructor stub
+}
+
+qint64 CpuLoad::read()
+{
+ static QChar space(' ');
+ if (!_file.open(QIODevice::ReadOnly)) {
+ return -1;
+ }
+ char buffer[500];
+ _file.readLine(buffer, sizeof(buffer));
+ _file.close();
+ QString line(buffer);
+ QStringList list = line.split(space, QString::SkipEmptyParts);
+ if (list.length() < 8) {
+ return -1;
+ }
+ // "cpu", user, nice, system, idle, iowait, irq, softirq
+ qint64 load = 0, total = 0;
+ for (int i = 1; i < 8; ++i) {
+ const qint64 value = list.at(i).toLongLong();
+ if (i < 4 || i > 5) {
+ load += value;
+ }
+ total += value;
+ }
+ const qint64 ret = ((load - _lastLoad) * 1000) / (total - _lastTotal);
+ _lastTotal = total;
+ _lastLoad = load;
+ return ret;
+}
+
+const QList<qint64>& CpuLoad::getBars() const
+{
+ static QList<qint64> list;
+ return list;
+}
+
+qint64 CpuLoad::getMaximum()
+{
+ return 1000;
+}
diff --git a/src/datasource/cpuload.h b/src/datasource/cpuload.h
new file mode 100644
index 0000000..2a5a2cb
--- /dev/null
+++ b/src/datasource/cpuload.h
@@ -0,0 +1,22 @@
+#ifndef CPULOAD_H_
+#define CPULOAD_H_
+
+#include "idatasource.h"
+#include <QFile>
+
+class CpuLoad : public IDataSource {
+public:
+ CpuLoad();
+ virtual ~CpuLoad();
+
+ virtual qint64 read();
+ virtual const QList<qint64>& getBars() const;
+ virtual qint64 getMaximum();
+
+private:
+ qint64 _lastLoad;
+ qint64 _lastTotal;
+ QFile _file;
+};
+
+#endif /* CPULOAD_H_ */
diff --git a/src/datasource/idatasource.h b/src/datasource/idatasource.h
new file mode 100644
index 0000000..4639d57
--- /dev/null
+++ b/src/datasource/idatasource.h
@@ -0,0 +1,16 @@
+#ifndef IDATASOURCE_H_
+#define IDATASOURCE_H_
+
+#include <QList>
+
+class IDataSource {
+public:
+ IDataSource() {};
+ virtual ~IDataSource() {};
+
+ virtual qint64 read() = 0;
+ virtual const QList<qint64>& getBars() const = 0;
+ virtual qint64 getMaximum() = 0;
+};
+
+#endif /* IDATASOURCE_H_ */
diff --git a/src/datasource/networkspeed.cpp b/src/datasource/networkspeed.cpp
new file mode 100644
index 0000000..8888fd4
--- /dev/null
+++ b/src/datasource/networkspeed.cpp
@@ -0,0 +1,50 @@
+#include "networkspeed.h"
+
+NetworkSpeed::NetworkSpeed() :
+ _lastBytes(0),
+ _lastMs(0),
+ _file("/sys/class/net/eth0/statistics/rx_bytes")
+{
+ _timer.start();
+}
+
+NetworkSpeed::~NetworkSpeed()
+{
+ // TODO Auto-generated destructor stub
+}
+
+qint64 NetworkSpeed::read()
+{
+ char buffer[500];
+ qint64 ret, now;
+ if (!_file.open(QIODevice::ReadOnly)) {
+ return -1;
+ }
+ now = _timer.elapsed();
+ _file.readLine(buffer, sizeof(buffer));
+ _file.close();
+ QString line(buffer);
+ const qint64 counter = (qint64)line.toLongLong();
+ if (_lastBytes == 0) {
+ ret = 0;
+ } else {
+ ret = counter - _lastBytes;
+ }
+ if (_lastMs < now) {
+ ret = (ret * 1000) / (now - _lastMs);
+ }
+ _lastMs = now;
+ _lastBytes = counter;
+ return ret;
+}
+
+const QList<qint64>& NetworkSpeed::getBars() const
+{
+ static QList<qint64> list = QList<qint64>() << ((qint64)1024 * 1024 * 10);
+ return list;
+}
+
+qint64 NetworkSpeed::getMaximum()
+{
+ return ((qint64)1024 * 1024 * 100);
+}
diff --git a/src/datasource/networkspeed.h b/src/datasource/networkspeed.h
new file mode 100644
index 0000000..482f4cd
--- /dev/null
+++ b/src/datasource/networkspeed.h
@@ -0,0 +1,24 @@
+#ifndef NETWORKSPEED_H_
+#define NETWORKSPEED_H_
+
+#include "idatasource.h"
+#include <QElapsedTimer>
+#include <QFile>
+
+class NetworkSpeed : public IDataSource {
+public:
+ NetworkSpeed();
+ virtual ~NetworkSpeed();
+
+ virtual qint64 read();
+ virtual const QList<qint64>& getBars() const;
+ virtual qint64 getMaximum();
+
+private:
+ qint64 _lastBytes;
+ qint64 _lastMs;
+ QElapsedTimer _timer;
+ QFile _file;
+};
+
+#endif /* NETWORKSPEED_H_ */
diff --git a/src/graphwidget.cpp b/src/graphwidget.cpp
new file mode 100644
index 0000000..ec15026
--- /dev/null
+++ b/src/graphwidget.cpp
@@ -0,0 +1,95 @@
+#include "graphwidget.h"
+#include "datasource/idatasource.h"
+#include <QDebug>
+#include <QResizeEvent>
+#include <QPaintEvent>
+#include <QPainter>
+
+const QColor GraphWidget::LINE_COLOR = QColor::fromRgb(20, 255, 80);
+const QColor GraphWidget::BACK_COLOR = QColor::fromRgb(10, 0, 20);
+const QColor GraphWidget::BAR_COLOR = QColor::fromRgb(200, 200, 200);
+
+GraphWidget::GraphWidget(QWidget* parent)
+ : QWidget(parent),
+ _source(NULL),
+ _histPos(0),
+ _vScale(0),
+ _doubleSpace(false)
+{
+ memset(_history, 0, sizeof(*_history) * HISTSIZE);
+}
+
+GraphWidget::~GraphWidget()
+{
+ delete _source;
+}
+
+void GraphWidget::setDataSource(IDataSource* source)
+{
+ delete _source;
+ _source = source;
+ memset(_history, 0, sizeof(*_history) * HISTSIZE);
+ _vScale = (float)height() / (float)_source->getMaximum();
+ qDebug() << "sDS " << _vScale;
+ update();
+}
+
+void GraphWidget::readNextValue()
+{
+ if (_source == NULL)
+ return;
+ //
+ _history[_histPos] = _source->read();
+ _histPos = (_histPos + 1) % HISTSIZE;
+ if (_doubleSpace && _histPos % 2 == 1) {
+ _history[_histPos] = _history[(_histPos + HISTSIZE - 1) % HISTSIZE];
+ update(_updateRectSmall);
+ } else {
+ update();
+ }
+}
+
+void GraphWidget::resizeEvent(QResizeEvent * event)
+{
+ const QSize &size = event->size();
+ _updateRectSmall = QRect(size.width() - 1, 0, 1, size.height());
+ if (_source != NULL) {
+ _vScale = (float)size.height() / (float)_source->getMaximum();
+ }
+ _doubleSpace = (width() < 400);
+ update();
+}
+
+void GraphWidget::paintEvent(QPaintEvent * event)
+{
+ qint64 value;
+ int x, y;
+ const QRect &rect = event->rect();
+ QPainter painter;
+ painter.begin(this);
+ painter.fillRect(rect, BACK_COLOR);
+ if (_source == NULL)
+ return;
+ painter.setPen(LINE_COLOR);
+ const int offset = HISTSIZE + HISTSIZE + _histPos - (this->width() - rect.x()) * (_doubleSpace ? 2 : 1);
+ // TODO: double space
+ for (int index = 0; index < rect.width(); ++index) {
+ x = rect.x() + index;
+ if (_doubleSpace) {
+ value = (_history[(offset + index * 2) % HISTSIZE] + _history[(offset + index * 2 + 1) % HISTSIZE]) / 2;
+ } else {
+ value = _history[(offset + index) % HISTSIZE];
+ }
+ y = height() - int(value * _vScale);
+ painter.drawLine(x, y, x, height());
+ }
+ const QList<qint64> &bars = _source->getBars();
+ if (!bars.empty()) {
+ painter.setPen(BAR_COLOR);
+ for (QList<qint64>::const_iterator it = bars.begin(); it != bars.end(); ++it) {
+ y = height() - int(*it * _vScale);
+ painter.drawLine(rect.left(), y, rect.right() + 1, y);
+ }
+ }
+ painter.end();
+}
diff --git a/src/graphwidget.h b/src/graphwidget.h
new file mode 100644
index 0000000..f43e0db
--- /dev/null
+++ b/src/graphwidget.h
@@ -0,0 +1,33 @@
+#ifndef GRAPHWIDGET_H_
+#define GRAPHWIDGET_H_
+
+#include <QWidget>
+
+class IDataSource;
+
+class GraphWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ GraphWidget(QWidget* parent = NULL);
+ virtual ~GraphWidget();
+
+ void setDataSource(IDataSource* source);
+ void readNextValue();
+
+protected:
+ virtual void resizeEvent(QResizeEvent * event);
+ virtual void paintEvent(QPaintEvent * event);
+
+private:
+ static const int HISTSIZE = 2000;
+ static const QColor LINE_COLOR, BACK_COLOR, BAR_COLOR;
+ IDataSource* _source;
+ qint64 _history[HISTSIZE];
+ int _histPos;
+ float _vScale;
+ bool _doubleSpace;
+ QRect _updateRectSmall;
+};
+
+#endif /* GRAPHWIDGET_H_ */
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..d5b71fb
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,16 @@
+#include "speedcheck.h"
+#include <QApplication>
+#include <QMessageBox>
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ if (argc != 2) {
+ QMessageBox::critical(NULL, "Error", "Need one argument: file name");
+ return 1;
+ }
+ SpeedCheck main(QString::fromLocal8Bit(argv[1]));
+ main.show();
+ app.exec();
+ return 0;
+}
diff --git a/src/speedcheck.cpp b/src/speedcheck.cpp
new file mode 100644
index 0000000..8ff8c93
--- /dev/null
+++ b/src/speedcheck.cpp
@@ -0,0 +1,81 @@
+#include "speedcheck.h"
+#include "ui_speedcheck.h"
+#include "copythread.h"
+#include "datasource/cpuload.h"
+#include "datasource/networkspeed.h"
+
+#include <QCoreApplication>
+#include <QMessageBox>
+#include <QFile>
+#include <QDebug>
+#include <QTimer>
+
+SpeedCheck::SpeedCheck(QString fileName)
+ : _ui(new Ui::MainWindow),
+ _thread(NULL),
+ _doQuit(false),
+ _fileName(fileName)
+{
+ _ui->setupUi(this);
+ connect(_ui->btnStart, SIGNAL(clicked(bool)), this, SLOT(startClicked(bool)));
+ connect(_ui->btnQuit, SIGNAL(clicked(bool)), this, SLOT(quitClicked(bool)));
+ _timer.setInterval(200);
+ connect(&_timer, SIGNAL(timeout()), this, SLOT(updateTimer()));
+}
+
+SpeedCheck::~SpeedCheck()
+{
+
+}
+
+void SpeedCheck::logMessage(QString message)
+{
+ qDebug() << message;
+ _ui->statusBar->showMessage(message);
+}
+
+void SpeedCheck::startClicked(bool)
+{
+ QFile *file = new QFile(_fileName);
+ if (!file->open(QIODevice::ReadOnly)) {
+ QMessageBox::critical(this, trUtf8("Error"), trUtf8("Could not open %1 for reading.").arg(_fileName));
+ return;
+ }
+ _ui->picCpu->setDataSource(new CpuLoad());
+ _ui->picSpeed->setDataSource(new NetworkSpeed());
+ _ui->btnStart->setDisabled(true);
+ delete _thread;
+ _thread = new CopyThread(file, this);
+ connect(_thread, SIGNAL(logMessage(QString)), this, SLOT(logMessage(QString)), Qt::QueuedConnection);
+ connect(_thread, SIGNAL(finished()), this, SLOT(testFinished()), Qt::QueuedConnection);
+ _timer.start();
+ _thread->start();
+}
+
+void SpeedCheck::quitClicked(bool)
+{
+ if (_thread != NULL && _thread->isRunning()) {
+ _doQuit = true;
+ _thread->stop();
+ }
+ if (_thread == NULL || !_thread->isRunning()) {
+ QCoreApplication::instance()->quit();
+ }
+}
+
+void SpeedCheck::testFinished()
+{
+ _timer.stop();
+ delete _thread;
+ _thread = NULL;
+ if (_doQuit) {
+ QCoreApplication::instance()->quit();
+ }
+ _ui->btnStart->setEnabled(true);
+}
+
+void SpeedCheck::updateTimer()
+{
+ _ui->picCpu->readNextValue();
+ _ui->picSpeed->readNextValue();
+}
diff --git a/src/speedcheck.h b/src/speedcheck.h
new file mode 100644
index 0000000..fd54605
--- /dev/null
+++ b/src/speedcheck.h
@@ -0,0 +1,35 @@
+#ifndef SPEEDCHECK_H_
+#define SPEEDCHECK_H_
+
+#include <QMainWindow>
+#include <QTimer>
+
+namespace Ui
+{
+ class MainWindow;
+}
+class CopyThread;
+
+class SpeedCheck : public QMainWindow
+{
+ Q_OBJECT
+public:
+ SpeedCheck(QString fileName);
+ virtual ~SpeedCheck();
+
+private slots:
+ void logMessage(QString message);
+ void startClicked(bool);
+ void quitClicked(bool);
+ void testFinished();
+ void updateTimer();
+
+private:
+ Ui::MainWindow *_ui;
+ CopyThread *_thread;
+ volatile bool _doQuit;
+ QString _fileName;
+ QTimer _timer;
+};
+
+#endif /* SPEEDCHECK_H_ */
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..bc24687
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,6 @@
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+#define UNUSED __attribute__ ((unused))
+
+#endif
diff --git a/src/ui/speedcheck.ui b/src/ui/speedcheck.ui
new file mode 100644
index 0000000..2f98f3b
--- /dev/null
+++ b/src/ui/speedcheck.ui
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>SpeedCheck</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="GraphWidget" name="picSpeed" native="true"/>
+ </item>
+ <item>
+ <widget class="GraphWidget" name="picCpu" native="true"/>
+ </item>
+ <item>
+ <widget class="QFrame" name="frame_3">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="sizeIncrement">
+ <size>
+ <width>0</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>32</height>
+ </size>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="btnStart">
+ <property name="text">
+ <string>Start</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnQuit">
+ <property name="text">
+ <string>Quit</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>GraphWidget</class>
+ <extends>QWidget</extends>
+ <header>graphwidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>