322 lines
7.3 KiB
C++
322 lines
7.3 KiB
C++
#include "qgapplicationperformance.h"
|
|
|
|
#include <QTimerEvent>
|
|
#include <QElapsedTimer>
|
|
#include <QDebug>
|
|
|
|
#include <windows.h>
|
|
#include <psapi.h>
|
|
#include <stdint.h>
|
|
|
|
static QgApplicationPerformance* globalInstance;
|
|
|
|
struct MyCounters
|
|
{
|
|
unsigned long refresh_rate;
|
|
|
|
float cpu;
|
|
float cpu_peek;
|
|
float mem;
|
|
float mem_peek;
|
|
|
|
uint64_t kt;
|
|
uint64_t ut;
|
|
uint64_t tt;
|
|
|
|
unsigned int cores;
|
|
|
|
int tid;
|
|
|
|
unsigned long long net_bytes;
|
|
unsigned long long net_bytes_period;
|
|
float net_band;
|
|
|
|
unsigned net_index;
|
|
|
|
QString hAddress;
|
|
bool calculate(QElapsedTimer& t); //unsigned long period_ms);
|
|
};
|
|
|
|
static MyCounters myCounters;
|
|
|
|
QgApplicationPerformance::QgApplicationPerformance(QObject *parent) : QObject(parent)
|
|
{
|
|
myCounters.refresh_rate=2;
|
|
net_index=0;
|
|
myCounters.net_index=0;
|
|
}
|
|
|
|
|
|
QgApplicationPerformance& QgApplicationPerformance::instance()
|
|
{
|
|
if (!globalInstance)
|
|
{
|
|
globalInstance=new QgApplicationPerformance;
|
|
|
|
myCounters.tid=0;
|
|
|
|
//globalInstance->startTimer(myCounters.refresh_rate*1000, Qt::PreciseTimer);
|
|
myCounters.ut=0;
|
|
myCounters.kt=0;
|
|
myCounters.tt=0;
|
|
myCounters.cores=1;
|
|
|
|
SYSTEM_INFO sysInfo;
|
|
GetSystemInfo(&sysInfo);
|
|
myCounters.cores=sysInfo.dwNumberOfProcessors>0 ? sysInfo.dwNumberOfProcessors : 1;
|
|
|
|
globalInstance->setRefreshRate(2);
|
|
|
|
myCounters.calculate(globalInstance->elapsedTimer);
|
|
|
|
globalInstance->elapsedTimer.start();
|
|
}
|
|
return *globalInstance;
|
|
}
|
|
|
|
void QgApplicationPerformance::timerEvent(QTimerEvent* evn)
|
|
{
|
|
if (evn->timerId()==myCounters.tid)
|
|
{
|
|
//qint64 elapsed=elapsedTimer.elapsed();
|
|
if (myCounters.calculate(elapsedTimer)) //myCounters.refresh_rate*1000))
|
|
Q_EMIT countersUpdated();
|
|
|
|
evn->accept();
|
|
}
|
|
else
|
|
QObject::timerEvent(evn);
|
|
}
|
|
|
|
void QgApplicationPerformance::setRefreshRate(unsigned long seconds)
|
|
{
|
|
myCounters.refresh_rate=seconds;
|
|
if (myCounters.tid)
|
|
{
|
|
killTimer(myCounters.tid);
|
|
myCounters.tid=0;
|
|
}
|
|
myCounters.tid=globalInstance->startTimer(myCounters.refresh_rate*1000);
|
|
}
|
|
|
|
void QgApplicationPerformance::setNetworkInterfaceIndex(unsigned int index, const QString& hAddress)
|
|
{
|
|
myCounters.net_index=index;
|
|
myCounters.hAddress=hAddress;
|
|
}
|
|
|
|
void QgApplicationPerformance::reset()
|
|
{
|
|
if (myCounters.tid)
|
|
killTimer(myCounters.tid);
|
|
|
|
myCounters.tid=0;
|
|
|
|
elapsedTimer.invalidate();
|
|
|
|
myCounters.ut=0;
|
|
myCounters.kt=0;
|
|
myCounters.tt=0;
|
|
myCounters.mem_peek=0;
|
|
myCounters.cpu_peek=0;
|
|
myCounters.mem=0;
|
|
myCounters.cpu=0;
|
|
|
|
myCounters.net_band=0;
|
|
myCounters.net_bytes=0;
|
|
myCounters.net_bytes_period=0;
|
|
|
|
myCounters.calculate(elapsedTimer);
|
|
setRefreshRate(myCounters.refresh_rate);
|
|
}
|
|
|
|
unsigned long QgApplicationPerformance::refreshRate() const
|
|
{
|
|
return myCounters.refresh_rate;
|
|
}
|
|
|
|
unsigned int QgApplicationPerformance::cpuUsage() const
|
|
{
|
|
return myCounters.cpu;
|
|
}
|
|
|
|
unsigned int QgApplicationPerformance::peekCpuUsage() const
|
|
{
|
|
return myCounters.cpu_peek;
|
|
}
|
|
|
|
|
|
unsigned long QgApplicationPerformance::memoryUsageKiB() const
|
|
{
|
|
return myCounters.mem/1024;
|
|
}
|
|
|
|
unsigned long QgApplicationPerformance::peekMemoryUsageKiB() const
|
|
{
|
|
return myCounters.mem_peek/1024;
|
|
}
|
|
|
|
QString QgApplicationPerformance::toString()
|
|
{
|
|
return QString("%1%(%2%), %3MB/%4MB, N: %5%(%6KB) @%7")
|
|
.arg(cpuUsage()).arg(peekCpuUsage()).arg(memoryUsageKiB()/1000).arg(peekMemoryUsageKiB()/1000)
|
|
.arg(myCounters.net_band, 0, 'f', 2).arg(myCounters.net_bytes_period).arg(myCounters.hAddress);
|
|
|
|
}
|
|
|
|
void QgApplicationPerformance::updateCounters()
|
|
{
|
|
}
|
|
|
|
//
|
|
static unsigned long long GetMemoryUsage()
|
|
{
|
|
PROCESS_MEMORY_COUNTERS_EX memInfo;
|
|
memInfo.cb=sizeof memInfo;
|
|
auto ok=GetProcessMemoryInfo(GetCurrentProcess(),
|
|
(PROCESS_MEMORY_COUNTERS*)&memInfo,
|
|
sizeof memInfo);
|
|
if (ok)
|
|
{
|
|
return memInfo.PrivateUsage; //WorkingSetSize;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool GetNetworkLoad(unsigned int index, unsigned long long &bytes, unsigned long long &speed);
|
|
|
|
bool MyCounters::calculate(QElapsedTimer & timer)
|
|
{
|
|
auto m=GetMemoryUsage();
|
|
if (m>myCounters.mem_peek)
|
|
myCounters.mem_peek=m;
|
|
myCounters.mem=m;
|
|
|
|
FILETIME pct;
|
|
FILETIME pext;
|
|
FILETIME pkt;
|
|
FILETIME put;
|
|
|
|
auto period_ms=timer.isValid() ? timer.elapsed() : 0;
|
|
auto ok=GetProcessTimes(GetCurrentProcess(), &pct, &pext, &pkt, &put);
|
|
if (ok)
|
|
{
|
|
timer.start();
|
|
uint64_t k=pkt.dwHighDateTime;
|
|
k=k<<32;
|
|
k|=uint64_t(pkt.dwLowDateTime);
|
|
|
|
uint64_t u=put.dwHighDateTime;
|
|
u=u<<32;
|
|
u|=uint64_t(put.dwLowDateTime);
|
|
|
|
if (period_ms)
|
|
{
|
|
uint64_t period_us=period_ms;
|
|
period_us=period_us*10;
|
|
|
|
uint64_t dk=k-myCounters.kt;
|
|
uint64_t du=u-myCounters.ut;
|
|
|
|
//From 100ns to us
|
|
dk=dk/10;
|
|
du=du/10;
|
|
|
|
uint64_t tot_us=dk+du;
|
|
|
|
double cpu_usage=(double(tot_us)/double(period_us))/cores;
|
|
|
|
myCounters.cpu=(cpu_usage+0.5);
|
|
if (myCounters.cpu>cpu_peek)
|
|
myCounters.cpu_peek=myCounters.cpu;
|
|
}
|
|
kt=k;
|
|
ut=u;
|
|
|
|
//return true;
|
|
}
|
|
|
|
if (net_index)
|
|
{
|
|
unsigned long long bytes;
|
|
unsigned long long speed;
|
|
if (!GetNetworkLoad(net_index, bytes, speed))
|
|
return true;
|
|
if (speed>0)
|
|
{
|
|
if (period_ms)
|
|
{
|
|
float seconds=float(period_ms)*0.001;
|
|
unsigned long long d=bytes-net_bytes;
|
|
//float ds=d*float(period_ms*10000);
|
|
net_bytes_period=(d/seconds)/1000; //ds/(period_ms*10000);
|
|
if (speed)
|
|
{
|
|
float s=(float(speed)/8)*seconds;
|
|
float b=d/s;
|
|
b=b*100;
|
|
net_band=b;
|
|
}
|
|
}
|
|
net_bytes=bytes;
|
|
//net_band=0;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#include <iphlpapi.h>
|
|
|
|
#if 0
|
|
struct myiftable_t{
|
|
DWORD dwNumEntries;
|
|
MIB_IFROW table[42];
|
|
};
|
|
static myiftable_t static_iftab;
|
|
static MIB_IFTABLE* iftab;
|
|
#endif
|
|
|
|
static MIB_IFROW* ifrow;
|
|
static MIB_IFROW saved_ifrow;
|
|
static bool net_info_error;
|
|
|
|
static bool GetNetworkLoad(unsigned int index, unsigned long long& bytes, unsigned long long &speed)
|
|
{
|
|
bytes=0;
|
|
speed=1;
|
|
if (net_info_error)
|
|
return false;
|
|
#if 0
|
|
if (!ifrow)
|
|
{
|
|
DWORD dwSize=sizeof static_iftab;
|
|
iftab=(MIB_IFTABLE*)&static_iftab;
|
|
|
|
DWORD r=GetIfTable(iftab, &dwSize, 0);
|
|
if (r==ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
iftab=(MIB_IFTABLE*)new char[dwSize+100];
|
|
memset(iftab, dwSize, 0);
|
|
r=GetIfTable(iftab, &dwSize, 0);
|
|
}
|
|
|
|
if (r!=NO_ERROR)
|
|
{
|
|
net_info_error=true;
|
|
return false;
|
|
}
|
|
saved_ifrow.dwIndex=iftab->table[20].dwIndex;
|
|
qDebug()<<"Perf-mon: ETH"<<saved_ifrow.dwIndex;
|
|
ifrow=&saved_ifrow;
|
|
}
|
|
#else
|
|
saved_ifrow.dwIndex=index;
|
|
ifrow=&saved_ifrow;
|
|
#endif
|
|
GetIfEntry(ifrow);
|
|
unsigned long long total=ifrow->dwInOctets+ifrow->dwOutOctets;
|
|
bytes=total;
|
|
speed=ifrow->dwSpeed;
|
|
return true;
|
|
}
|