#include #include "qappctrl.h" #include "../../src/defines.h" ///////////////////////////////////////////////////////////////////////////// #define _INVALID_SLOT_INDEX -1 #define _APP_CTRL_MAX_SLOTS ((int)(sizeof(appid_t) * 8)) #define _APP_INDEX_FROM_APP_ID(aid) (ffsll(aid) - 1) #define _IS_POWER_OF_2(x) (!!(x) && !((x) & ((x) - 1))) #define _IS_VALID_APP_ID(i) _IS_POWER_OF_2(i) #define _TIMESPEC_2_US(ts) (((clock64_t)(ts).tv_sec) * 1000000LL + ((clock64_t)(ts).tv_nsec) / 1000LL) #define _TIMESPEC_DIFF_US(ts1, ts2) (_TIMESPEC_2_US(ts1) - _TIMESPEC_2_US(ts2)) #define _MIN_TIMER_INT 20 ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// QGfaAppInfo::QGfaAppInfo(int nIndex, QObject *pParent) : QObject(pParent), m_state(GIAS_StateNotRunning), m_nIndex(nIndex), m_cycInt(0), m_cycCur(0), m_cycMin(0), m_cycMax(0), m_wktCur(0), m_wktMin(0), m_wktMax(0), m_upTime(0), m_cpuTime(0.0), m_cpuPercCur(0.0), m_cpuPercAvg(0.0), m_vmPeak(0), m_vmSize(0), m_vmHWM(0), m_vmRSS(0), m_appSize(0) { m_nAppID = 1ull << m_nIndex; setStateText(m_state); } QGfaAppInfo::~QGfaAppInfo(void) { this->disconnect(); } ///////////////////////////////////////////////////////////////////////////// appid_t QGfaAppInfo::appId(void) const { return m_nAppID; } ///////////////////////////////////////////////////////////////////////////// int QGfaAppInfo::state(void) const { return m_state; } bool QGfaAppInfo::setState(int val) { if(m_state != val) { m_state = val; emit stateChanged(val); setStateText(val); return true; } return false; } ///////////////////////////////////////////////////////////////////////////// QString QGfaAppInfo::stateText(void) const { return m_stateText; } void QGfaAppInfo::setStateText(int val) { QString sval = ::GfaIpcAppCtrlGetStateText((GfaIpcAppStates)val); if(m_stateText != sval) { m_stateText = sval; emit stateTextChanged(sval); } } ///////////////////////////////////////////////////////////////////////////// QString QGfaAppInfo::name(void) const { return m_name; } void QGfaAppInfo::setName(const QString &val) { if(m_name != val) { m_name = val; emit nameChanged(val); } } ///////////////////////////////////////////////////////////////////////////// quint64 QGfaAppInfo::cycInt(void) const { return m_cycInt; } quint64 QGfaAppInfo::cycCur(void) const { return m_cycCur; } quint64 QGfaAppInfo::cycMin(void) const { return m_cycMin; } quint64 QGfaAppInfo::cycMax(void) const { return m_cycMax; } quint64 QGfaAppInfo::wktCur(void) const { return m_wktCur; } quint64 QGfaAppInfo::wktMin(void) const { return m_wktMin; } quint64 QGfaAppInfo::wktMax(void) const { return m_wktMax; } quint64 QGfaAppInfo::upTime(void) const { return m_upTime; } double QGfaAppInfo::cpuTime(void) const { return m_cpuTime; } double QGfaAppInfo::cpuCur(void) const { return m_cpuPercCur; } double QGfaAppInfo::cpuAvg(void) const { return m_cpuPercAvg; } quint32 QGfaAppInfo::vmPeak(void) const { return m_vmPeak; } quint32 QGfaAppInfo::vmSize(void) const { return m_vmSize; } quint32 QGfaAppInfo::vmHWM(void) const { return m_vmHWM; } quint32 QGfaAppInfo::vmRSS(void) const { return m_vmRSS; } quint32 QGfaAppInfo::appSize(void) const { return m_appSize; } void QGfaAppInfo::setAppSize(quint32 size, GfaIpcAppStates state) { if((state > GIAS_StateNotRunning) && (state < GIAS_Invalid)) { if(m_appSize != size) { m_appSize = size; emit appSizeChanged(m_appSize); } } else { if(m_appSize != 0) { m_appSize = 0; emit appSizeChanged(m_appSize); } } } void QGfaAppInfo::setAppMemInfo(LPCGFA_APPCTRL_APPMEM pam, GfaIpcAppStates state, bool bDoHeavyLoadUpdate) { UNUSED(state); if(pam) { if(bDoHeavyLoadUpdate) { if(m_vmPeak != pam->vmPeak) { m_vmPeak = pam->vmPeak; emit vmPeakChanged(m_vmPeak); } if(m_vmSize != pam->vmSize) { m_vmSize = pam->vmSize; emit vmSizeChanged(m_vmSize); } if(m_vmHWM != pam->vmHWM) { m_vmHWM = pam->vmHWM; emit vmHWMChanged(m_vmHWM); } if(m_vmRSS != pam->vmRSS) { m_vmRSS = pam->vmRSS; emit vmRSSChanged(m_vmRSS); } } } else if(state != GIAS_Hanging) { if(m_vmPeak != 0) { m_vmPeak = 0; emit vmPeakChanged(m_vmPeak); } if(m_vmSize != 0) { m_vmSize = 0; emit vmSizeChanged(m_vmSize); } if(m_vmHWM != 0) { m_vmHWM = 0; emit vmHWMChanged(m_vmHWM); } if(m_vmRSS != 0) { m_vmRSS = 0; emit vmRSSChanged(m_vmRSS); } } } void QGfaAppInfo::setAppTimes(LPCGFA_APPCTRL_APPTIMES pat, GfaIpcAppStates state, bool bDoHeavyLoadUpdate) { if(pat) { if(m_cycInt != (quint64)pat->nCyclePresetUs) { m_cycInt = (quint64)pat->nCyclePresetUs; emit cycIntChanged(m_cycInt); } if(state == GIAS_Running) { if(m_cycMin != (quint64)pat->nCycleMinUs) { m_cycMin = (quint64)pat->nCycleMinUs; emit cycMinChanged(m_cycMin); } if(m_cycMax != (quint64)pat->nCycleMaxUs) { m_cycMax = (quint64)pat->nCycleMaxUs; emit cycMaxChanged(m_cycMax); } if(m_wktMin != (quint64)pat->nWorkMinUs) { m_wktMin = (quint64)pat->nWorkMinUs; emit wktMinChanged(m_wktMin); } if(m_wktMax != (quint64)pat->nWorkMaxUs) { m_wktMax = (quint64)pat->nWorkMaxUs; emit wktMaxChanged(m_wktMax); } } else { if(m_cycCur != 0) { m_cycCur = 0; emit cycCurChanged(m_cycCur); } if(m_wktCur != 0) { m_wktCur = 0; emit wktCurChanged(m_wktCur); } } if(bDoHeavyLoadUpdate) { quint64 upTime = time(NULL) - pat->nTsStart; if(m_upTime != upTime) { m_upTime = upTime; emit upTimeChanged(m_upTime); } if(state == GIAS_Running) { if(m_cycCur != (quint64)pat->nCycleLastUs) { m_cycCur = (quint64)pat->nCycleLastUs; emit cycCurChanged(m_cycCur); } if(m_wktCur != (quint64)pat->nWorkLastUs) { m_wktCur = (quint64)pat->nWorkLastUs; emit wktCurChanged(m_wktCur); } } if(state != GIAS_Hanging) { if(m_cpuTime != pat->fCpuTime) { m_cpuTime = pat->fCpuTime; emit cpuTimeChanged(m_cpuTime); } if(m_cpuPercCur != pat->fCpuCur) { m_cpuPercCur = pat->fCpuCur; emit cpuCurChanged(m_cpuPercCur); } if(m_cpuPercAvg != pat->fCpuAvg) { m_cpuPercAvg = pat->fCpuAvg; emit cpuAvgChanged(m_cpuPercAvg); } } } } else { if(m_cycInt != 0) { m_cycInt = 0; emit cycIntChanged(m_cycInt); } if(m_cycCur != 0) { m_cycCur = 0; emit cycCurChanged(m_cycCur); } if(m_wktCur != 0) { m_wktCur = 0; emit wktCurChanged(m_wktCur); } if(state == GIAS_Hanging) { if(m_cpuTime != -1) { m_cpuTime = -1; emit cpuTimeChanged(m_cpuTime); } if(m_cpuPercCur != -1) { m_cpuPercCur = -1; emit cpuCurChanged(m_cpuPercCur); } if(m_cpuPercAvg != -1) { m_cpuPercAvg = -1; emit cpuAvgChanged(m_cpuPercAvg); } } else { if(m_cycMin != 0) { m_cycMin = 0; emit cycMinChanged(m_cycMin); } if(m_cycMax != 0) { m_cycMax = 0; emit cycMaxChanged(m_cycMax); } if(m_wktMin != 0) { m_wktMin = 0; emit wktMinChanged(m_wktMin); } if(m_wktMax != 0) { m_wktMax = 0; emit wktMaxChanged(m_wktMax); } if(m_upTime != 0) { m_upTime = 0; emit upTimeChanged(m_upTime); } if(m_cpuTime != 0) { m_cpuTime = 0; emit cpuTimeChanged(m_cpuTime); } if(m_cpuPercCur != 0) { m_cpuPercCur = 0; emit cpuCurChanged(m_cpuPercCur); } if(m_cpuPercAvg != 0) { m_cpuPercAvg = 0; emit cpuAvgChanged(m_cpuPercAvg); } } } } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppInfo::pause(void) { emit sendControlMessage(m_nAppID, GFA_APPCTRL_CTRLMSG_PAUSE); return true; } bool QGfaAppInfo::resume(void) { emit sendControlMessage(m_nAppID, GFA_APPCTRL_CTRLMSG_RESUME); return true; } bool QGfaAppInfo::stop(void) { emit sendControlMessage(m_nAppID, GFA_APPCTRL_CTRLMSG_STOP); return true; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// QGfaAppCtrl::QGfaAppCtrl(QObject *pParent) : QObject(pParent), m_hAC(NULL), m_nAppID(0), m_nTimerID(0), m_curPass(0), m_minPass(LLONG_MAX), m_maxPass(LLONG_MIN), m_avgPass(0), m_nEvtSrcs(0), m_nHeavyLoadUpdateIntervalUs(2500000) { for(int i = 0; i < _APP_CTRL_MAX_SLOTS; ++i) { QGfaAppInfo *pai = new QGfaAppInfo(i, this); connect(pai, SIGNAL(sendControlMessage(appid_t, ctrlmsg_t)), SLOT(onSendControlMessage(appid_t, ctrlmsg_t))); m_appInfo.append(pai); } memset(&m_tsLastHeavyLoadUpdate, 0, sizeof(m_tsLastHeavyLoadUpdate)); } QGfaAppCtrl::~QGfaAppCtrl(void) { Release(); for(int i = 0; i < _APP_CTRL_MAX_SLOTS; ++i) { QGfaAppInfo *pai = m_appInfo.at(i); delete pai; } } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::Create(appid_t nAppID, const char *pszDisplayName, int nTimerIntMs, clock64_t nHeavyLoadUpdateIntervalMs) { if(!m_hAC) { if(nTimerIntMs < _MIN_TIMER_INT) nTimerIntMs = _MIN_TIMER_INT; if(nHeavyLoadUpdateIntervalMs < (nTimerIntMs * 50)) nHeavyLoadUpdateIntervalMs = (nTimerIntMs * 50); if((m_hAC = ::GfaIpcAppCtrlAcquire(nAppID, pszDisplayName, 0, (clock64_t)(nTimerIntMs * 1000 * 2)))) { m_nAppID = nAppID; m_nHeavyLoadUpdateIntervalUs = nHeavyLoadUpdateIntervalMs * 1000; m_nTimerID = startTimer(nTimerIntMs, Qt::CoarseTimer); } } return !!m_hAC; } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::Release(void) { if(m_hAC) { killTimer(m_nTimerID); ::GfaIpcAppCtrlRelease(m_hAC); m_hAC = NULL; } } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::RegisterQmlTypes(QQmlEngine &rEng, int nVerMajor, int nVerMinor) { qmlRegisterUncreatableType("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaAppInfo", QStringLiteral("class not creatable in QML")); qmlRegisterUncreatableType("com.gfa.ipc.appctrl", nVerMajor, nVerMinor, "QGfaAppCtrl", QStringLiteral("class not creatable in QML")); rEng.rootContext()->setContextProperty(QStringLiteral("qGfaAppCtrl"), this); } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::PresetDisplayName(appid_t nAppID, const char *pszName) { if(m_hAC) return ::GfaIpcAppCtrlPresetDisplayName(m_hAC, nAppID, pszName); return false; } ///////////////////////////////////////////////////////////////////////////// bool QGfaAppCtrl::SubscribeStateEvents(appid_t nAppMask) { if(m_hAC) { nAppMask &= ~m_nAppID; m_nEvtSrcs |= nAppMask; return ::GfaIpcAppCtrlSubscribeStateEvents(m_hAC, nAppMask); } return false; } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::timerEvent(QTimerEvent *event) { static clock64_t nCurPass = 0; struct timespec tsEnterUpdate, tsLeaveUpdate; ::clock_gettime(CLOCK_MONOTONIC, &tsEnterUpdate); if((event->timerId() == m_nTimerID) && m_hAC) { HAPPINFO hAI; if((hAI = ::GfaIpcAppCtrlInfoUpdate(m_hAC, nCurPass))) { int b; appid_t app, nAppIdSrc; GFA_APPCTRL_APPTIMES at; GFA_APPCTRL_APPMEM am; char szDispName[128]; while((nAppIdSrc = ::GfaIpcAppCtrlGetNextStateEvtSrc(hAI))) { GfaIpcAppStates state = ::GfaIpcAppCtrlGetState(m_hAC, nAppIdSrc); int nIndex = appIndexFromAppID(nAppIdSrc); QGfaAppInfo &ai = *m_appInfo[nIndex]; bool bStateChanged = ai.setState(state); if(bStateChanged) { if(state == GIAS_Running) memset(&m_tsLastHeavyLoadUpdate, 0, sizeof(m_tsLastHeavyLoadUpdate)); else if(state != GIAS_Paused) { ai.setAppTimes(NULL, state); ai.setAppMemInfo(NULL, state); } } if((state >= GIAS_StateNotRunning) && (state <= GIAS_Paused)) { if(::GfaIpcAppCtrlGetDisplayName(m_hAC, nAppIdSrc, szDispName, sizeof(szDispName))) { ai.setName(szDispName); } } } nAppIdSrc = m_nEvtSrcs; bool bDontSaveLast = false, bUpdate = (_TIMESPEC_DIFF_US(tsEnterUpdate, m_tsLastHeavyLoadUpdate) >= m_nHeavyLoadUpdateIntervalUs); while(nAppIdSrc) { b = ffsll(nAppIdSrc) - 1; app = ((appid_t)0x1 << b); nAppIdSrc &= ~app; QGfaAppInfo &ai = *m_appInfo[b]; GfaIpcAppStates state = ::GfaIpcAppCtrlGetState(m_hAC, app); if(::GfaIpcAppCtrlGetAppMem(m_hAC, app, &am)) { ai.setAppMemInfo(&am, state, bUpdate); } if(::GfaIpcAppCtrlGetAppTimes(m_hAC, app, &at) >= 0) { if(!at.nCycleLastUs) { bDontSaveLast = true; continue; } ai.setAppTimes(&at, state, bUpdate); } size_t nSize = ::GfaIpcAppCtrlGetAppSize(m_hAC, app); ai.setAppSize((quint32)nSize, state); } if(bUpdate && !bDontSaveLast) m_tsLastHeavyLoadUpdate = tsEnterUpdate; } } ::clock_gettime(CLOCK_MONOTONIC, &tsLeaveUpdate); m_curPass = nCurPass = _TIMESPEC_DIFF_US(tsLeaveUpdate, tsEnterUpdate); if(m_minPass > m_curPass) { m_minPass = m_curPass; emit minPassChanged(m_minPass); } if(m_maxPass < m_curPass) { m_maxPass = m_curPass; emit maxPassChanged(m_maxPass); } if(!m_avgPass) { m_avgPass = m_curPass; emit avgPassChanged(m_avgPass); } else { static uint64_t nPasses = 0; ++nPasses; clock64_t avgPass = (m_avgPass + m_curPass) / 2; // clock64_t avgPass = (clock64_t)sqrt(double((m_avgPass * m_avgPass + m_curPass * m_curPass) / 2)); if(m_avgPass != avgPass) { m_avgPass = avgPass; if(!(nPasses % 50)) emit avgPassChanged(m_avgPass); } } } ///////////////////////////////////////////////////////////////////////////// void QGfaAppCtrl::onSendControlMessage(appid_t nAppID, ctrlmsg_t msg) { if(m_hAC) ::GfaIpcAppCtrlSendCtrlMsg(m_hAC, nAppID, msg); } ///////////////////////////////////////////////////////////////////////////// int QGfaAppCtrl::SetState(int nState) { if(m_hAC) ::GfaIpcAppCtrlSetState(m_hAC, (GfaIpcAppStates)nState); return GIAS_Invalid; } ///////////////////////////////////////////////////////////////////////////// quint64 QGfaAppCtrl::minPass(void) const { return m_minPass; } quint64 QGfaAppCtrl::maxPass(void) const { return m_maxPass; } quint64 QGfaAppCtrl::avgPass(void) const { return m_avgPass; } ///////////////////////////////////////////////////////////////////////////// int QGfaAppCtrl::appIndexFromAppID(quint64 nAppID) { if(_IS_VALID_APP_ID(nAppID)) return _APP_INDEX_FROM_APP_ID(nAppID); return _INVALID_SLOT_INDEX; } ///////////////////////////////////////////////////////////////////////////// QQmlListProperty QGfaAppCtrl::appInfo(void) { return QQmlListProperty(this, m_appInfo); }