SXXXXXXX_PyBusMonitor1553/cpp/GrifoScope/QgScope/qgapplicationperformance.cpp
2025-12-17 07:59:30 +01:00

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;
}