From c707aa9a5abd6d5d4c34465f1809af9a47bd58e2 Mon Sep 17 00:00:00 2001 From: timurhai Date: Mon, 23 Dec 2024 20:00:21 +0300 Subject: [PATCH] afanasy: afserverv sends to afwatch block tasks min and max running time. AfWatch can mark blocks with tasks max run time above this value. New network protocol version! References: #614. --- afanasy/src/include/afversion.h | 2 +- afanasy/src/libafanasy/blockdata.cpp | 2 - afanasy/src/libafanasy/blockdata.h | 6 +- afanasy/src/libafqt/qenvironment.cpp | 4 ++ afanasy/src/libafqt/qenvironment.h | 2 + afanasy/src/libafsql/dbjob.cpp | 2 +- afanasy/src/watch/blockinfo.cpp | 88 +++++++++++++++++++++++----- afanasy/src/watch/blockinfo.h | 7 ++- afanasy/src/watch/ctrljobs.cpp | 40 ++++++++++++- afanasy/src/watch/ctrljobs.h | 3 + afanasy/src/watch/itemjob.cpp | 4 +- 11 files changed, 134 insertions(+), 26 deletions(-) diff --git a/afanasy/src/include/afversion.h b/afanasy/src/include/afversion.h index 7f5c6a190..b8e738cf1 100644 --- a/afanasy/src/include/afversion.h +++ b/afanasy/src/include/afversion.h @@ -18,5 +18,5 @@ #pragma once -static const int AFVERSION = 80; +static const int AFVERSION = 81; diff --git a/afanasy/src/libafanasy/blockdata.cpp b/afanasy/src/libafanasy/blockdata.cpp index 27ce080bb..77302de72 100644 --- a/afanasy/src/libafanasy/blockdata.cpp +++ b/afanasy/src/libafanasy/blockdata.cpp @@ -667,10 +667,8 @@ void BlockData::v_readwrite(Msg *msg) rw_int32_t(p_tasks_waitrec, msg); rw_int32_t(p_tasks_waitdep, msg); rw_int32_t(p_tasks_suspended, msg); - /* NEW_VERSION rw_int32_t(p_tasks_run_time_min, msg); rw_int32_t(p_tasks_run_time_max, msg); - */ rw_int64_t(p_tasks_run_time_sum, msg); rw_int64_t(m_state, msg); diff --git a/afanasy/src/libafanasy/blockdata.h b/afanasy/src/libafanasy/blockdata.h index bbb977fd3..a1b34abf3 100644 --- a/afanasy/src/libafanasy/blockdata.h +++ b/afanasy/src/libafanasy/blockdata.h @@ -289,9 +289,9 @@ class BlockData : public Af inline int getProgressTasksWaitReconn() const { return p_tasks_waitrec; } inline int getProgressTasksWaitDep() const { return p_tasks_waitdep; } inline int getProgressTasksSuspended() const { return p_tasks_suspended; } - inline int getProgressTasksMinRunTime() const { return p_tasks_run_time_min; } - inline int getProgressTasksMaxRunTime() const { return p_tasks_run_time_max; } - inline long long getProgressTasksSumRunTime() const { return p_tasks_run_time_sum; } + inline int getProgressTasksRunTimeMin() const { return p_tasks_run_time_min; } + inline int getProgressTasksRunTimeMax() const { return p_tasks_run_time_max; } + inline long long getProgressTasksRunTimeSum() const { return p_tasks_run_time_sum; } inline void setState(uint32_t value) { m_state = value; } inline void setProgressTasksReady(int value) { p_tasks_ready = value; } diff --git a/afanasy/src/libafqt/qenvironment.cpp b/afanasy/src/libafqt/qenvironment.cpp index fa02bab4b..b6d361052 100644 --- a/afanasy/src/libafqt/qenvironment.cpp +++ b/afanasy/src/libafqt/qenvironment.cpp @@ -120,6 +120,8 @@ AttrColor QEnvironment::clr_textdone( "clr_textdone", "Done Text" AttrColor QEnvironment::clr_textmuted( "clr_textmuted", "Muted Text", AFGUI::CLR_TEXTMUTED ); AttrColor QEnvironment::clr_textstars( "clr_textstars", "Stars Text", AFGUI::CLR_TEXTSTARS ); +AttrNumber QEnvironment::jobs_run_time_max_secs("jobs_run_time_max_secs", "Job Item Run Time Max", 0); +AttrNumber QEnvironment::work_run_time_max_secs("work_run_time_max_secs", "Job Item Run Time Max", 0); AttrNumber QEnvironment::thumb_jobs_height("thumb_jobs_height", "Job Item Height", AFGUI::THUMB_JOBS_HEIGHT); AttrNumber QEnvironment::thumb_work_height("thumb_work_height", "Work Job Item Height", AFGUI::THUMB_JOBS_HEIGHT); AttrNumber QEnvironment::render_item_size ("render_item_size", "Render Item Size", AFGUI::RENDER_ITEM_SIZE ); @@ -171,6 +173,8 @@ QEnvironment::QEnvironment( const QString & i_name) ms_attrs_prefs.append(&showServerPort ); ms_attrs_prefs.append( &showOfflineNoise ); + ms_attrs_prefs.append(&jobs_run_time_max_secs); + ms_attrs_prefs.append(&work_run_time_max_secs); ms_attrs_prefs.append(&thumb_jobs_height); ms_attrs_prefs.append(&thumb_work_height); ms_attrs_prefs.append(&render_item_size ); diff --git a/afanasy/src/libafqt/qenvironment.h b/afanasy/src/libafqt/qenvironment.h index 4bf1c8f44..8f31cd0fb 100644 --- a/afanasy/src/libafqt/qenvironment.h +++ b/afanasy/src/libafqt/qenvironment.h @@ -148,6 +148,8 @@ class afqt::QEnvironment static QFont f_plotter; static QFont f_min; + static AttrNumber jobs_run_time_max_secs; + static AttrNumber work_run_time_max_secs; static AttrNumber thumb_jobs_height; static AttrNumber thumb_work_height; static AttrNumber render_item_size; diff --git a/afanasy/src/libafsql/dbjob.cpp b/afanasy/src/libafsql/dbjob.cpp index ea67f6c64..e6f3d1e54 100644 --- a/afanasy/src/libafsql/dbjob.cpp +++ b/afanasy/src/libafsql/dbjob.cpp @@ -63,7 +63,7 @@ void DBJob::add( const af::Job * i_job, std::list * o_queries) m_service = block->getService(); m_tasks_quantity = block->getTasksNum(); m_tasks_done = block->getProgressTasksDone(); - m_run_time_sum = block->getProgressTasksSumRunTime(); + m_run_time_sum = block->getProgressTasksRunTimeSum(); // Skip blocks with no run time: if( m_tasks_quantity == 0 ) continue; diff --git a/afanasy/src/watch/blockinfo.cpp b/afanasy/src/watch/blockinfo.cpp index 82be98165..c96b283cc 100644 --- a/afanasy/src/watch/blockinfo.cpp +++ b/afanasy/src/watch/blockinfo.cpp @@ -25,9 +25,10 @@ const int BlockInfo::Height = 48; const int BlockInfo::HeightCompact = 16; -BlockInfo::BlockInfo(const af::BlockData * i_data, Item * i_item, ListItems * i_listitems): +BlockInfo::BlockInfo(const af::BlockData * i_data, Item * i_item, ListItems * i_listitems, bool i_inworklist): m_item(i_item), m_listitems(i_listitems), + m_inworklist(i_inworklist), p_percentage(0), p_tasks_ready(0), @@ -42,7 +43,9 @@ BlockInfo::BlockInfo(const af::BlockData * i_data, Item * i_item, ListItems * i_ p_tasks_waitrec(0), p_error_hosts(0), p_avoid_hosts(0), - p_tasks_sumruntime(0), + p_tasks_runtimemin(0), + p_tasks_runtimemax(0), + p_tasks_runtimesum(0), errors_retries(-1), errors_avoid_host(-1), @@ -241,7 +244,9 @@ bool BlockInfo::update( const af::BlockData* block, int type) p_tasks_waitrec = block->getProgressTasksWaitReconn(); p_avoid_hosts = block->getProgressAvoidHostsNum(); p_error_hosts = block->getProgressErrorHostsNum(); - p_tasks_sumruntime = block->getProgressTasksSumRunTime(); + p_tasks_runtimemin = block->getProgressTasksRunTimeMin(); + p_tasks_runtimemax = block->getProgressTasksRunTimeMax(); + p_tasks_runtimesum = block->getProgressTasksRunTimeSum(); server_info = afqt::stoq(block->getSrvInfo()); @@ -362,9 +367,17 @@ void BlockInfo::refresh() str_right_top.clear(); if( Watch::isPadawan()) { - if ((p_tasks_done - p_tasks_skipped) > 0) str_right_top += QString(" Render Timings: Sum:%1 / Average:%2") - .arg(af::time2strHMS(p_tasks_sumruntime, true).c_str()) - .arg(af::time2strHMS(p_tasks_sumruntime/(p_tasks_done - p_tasks_skipped), true).c_str()); + QString timings; + if ((p_tasks_done - p_tasks_skipped) > 0) + timings += QString("Sum:%1 / Average:%2") + .arg(af::time2strHMS(p_tasks_runtimesum, true).c_str()) + .arg(af::time2strHMS(p_tasks_runtimesum/(p_tasks_done - p_tasks_skipped), true).c_str()); + if (p_tasks_runtimemin) + timings += QString(" Min:%1").arg(af::time2strHMS(p_tasks_runtimemin, true).c_str()); + if (p_tasks_runtimemax) + timings += QString(" Max:%1").arg(af::time2strHMS(p_tasks_runtimemax, true).c_str()); + if (timings.size()) + str_right_top += QString(" Render Timings: ") + timings; if(( errors_avoid_host >= 0 ) || ( errors_task_same_host >= 0 ) || ( errors_retries >= 0 )) str_right_top += Item::generateErrorsSolvingInfo( errors_avoid_host, errors_task_same_host, errors_retries); @@ -420,9 +433,17 @@ void BlockInfo::refresh() } else if( Watch::isJedi()) { - if ((p_tasks_done - p_tasks_skipped) > 0) str_right_top += QString(" Timings: Sum:%1/Avg:%2") - .arg(af::time2strHMS(p_tasks_sumruntime, true).c_str()) - .arg(af::time2strHMS(p_tasks_sumruntime/(p_tasks_done - p_tasks_skipped), true).c_str()); + QString timings; + if ((p_tasks_done - p_tasks_skipped) > 0) + timings += QString("Sum:%1/Avg:%2") + .arg(af::time2strHMS(p_tasks_runtimesum, true).c_str()) + .arg(af::time2strHMS(p_tasks_runtimesum/(p_tasks_done - p_tasks_skipped), true).c_str()); + if (p_tasks_runtimemin) + timings += QString(" Min:%1").arg(af::time2strHMS(p_tasks_runtimemin, true).c_str()); + if (p_tasks_runtimemax) + timings += QString(" Max:%1").arg(af::time2strHMS(p_tasks_runtimemax, true).c_str()); + if (timings.size()) + str_right_top += QString(" Timings: ") + timings; if(( errors_avoid_host >= 0 ) || ( errors_task_same_host >= 0 ) || ( errors_retries >= 0 )) str_right_top += Item::generateErrorsSolvingInfo( errors_avoid_host, errors_task_same_host, errors_retries); @@ -478,9 +499,17 @@ void BlockInfo::refresh() } else { - if ((p_tasks_done - p_tasks_skipped) > 0) str_right_top += QString(" rt:s%1/a%2") - .arg(af::time2strHMS(p_tasks_sumruntime, true).c_str()) - .arg(af::time2strHMS(p_tasks_sumruntime/(p_tasks_done - p_tasks_skipped), true).c_str()); + QString timings; + if ((p_tasks_done - p_tasks_skipped) > 0) + timings += QString("s:%1/a:%2") + .arg(af::time2strHMS(p_tasks_runtimesum, true).c_str()) + .arg(af::time2strHMS(p_tasks_runtimesum/(p_tasks_done - p_tasks_skipped), true).c_str()); + if (p_tasks_runtimemin) + timings += QString(" m:%1").arg(af::time2strHMS(p_tasks_runtimemin, true).c_str()); + if (p_tasks_runtimemax) + timings += QString(" M:%1").arg(af::time2strHMS(p_tasks_runtimemax, true).c_str()); + if (timings.size()) + str_right_top += QString(" rt: ") + timings; if(( errors_avoid_host >= 0 ) || ( errors_task_same_host >= 0 ) || ( errors_retries >= 0 )) str_right_top += Item::generateErrorsSolvingInfo( errors_avoid_host, errors_task_same_host, errors_retries); @@ -651,10 +680,41 @@ void BlockInfo::paint( QPainter * i_painter, const QStyleOptionViewItem &option, } } - // Paint border: - i_painter->setPen(afqt::QEnvironment::clr_outline.c ); i_painter->setBrush(Qt::NoBrush); + QColor borderColor(afqt::QEnvironment::clr_outline.c); + QPen borderPen(borderColor); + int run_time_max_sec = afqt::QEnvironment::jobs_run_time_max_secs.n; + if (m_inworklist) + run_time_max_sec = afqt::QEnvironment::work_run_time_max_secs.n; + if (p_tasks_runtimemax && run_time_max_sec && (p_tasks_runtimemax >= run_time_max_sec)) + { + int clr_badly[3] = {150, 80, 80}; + int clr_worse[3] = {250, 80, 80}; + float factor = float(p_tasks_runtimemax) / float(run_time_max_sec); + if (factor < 1) + { + factor = 1 - (1 - factor) * 4; + clr_worse[0] = clr_badly[0]; + clr_worse[1] = clr_badly[1]; + clr_worse[2] = clr_badly[2]; + clr_badly[0] = borderColor.red(); + clr_badly[1] = borderColor.green(); + clr_badly[2] = borderColor.blue(); + } + else + { + factor = factor - 1; + } + if (factor < 0) factor = 0; + if (factor > 1) factor = 1; + int clr[3] = {0,0,0}; + for (int i = 0; i < 3; i++) + clr[i] = int((1.0 - factor) * clr_badly[i] + factor * clr_worse[i]); + borderPen.setColor(QColor(clr[0], clr[1], clr[2])); + i_painter->setBrush(QColor(clr[0], clr[1], clr[2], 80)); + } + i_painter->setPen(borderPen); i_painter->drawRoundedRect(x+xoffset-3, y-1, w+4-xoffset, i_compact_display ? HeightCompact : Height, 3, 3); diff --git a/afanasy/src/watch/blockinfo.h b/afanasy/src/watch/blockinfo.h index 55216de33..99a2c07cf 100644 --- a/afanasy/src/watch/blockinfo.h +++ b/afanasy/src/watch/blockinfo.h @@ -20,7 +20,7 @@ class BlockInfo: public QObject Q_OBJECT public: - BlockInfo(const af::BlockData * i_data, Item * i_item, ListItems * i_listitems); + BlockInfo(const af::BlockData * i_data, Item * i_item, ListItems * i_listitems, bool i_inworklist = false); ~BlockInfo(); inline const QString & getName() const {return m_name;} @@ -53,7 +53,9 @@ class BlockInfo: public QObject int p_avoid_hosts; int p_error_hosts; long long p_capacity_total; - long long p_tasks_sumruntime; + int p_tasks_runtimemin; + int p_tasks_runtimemax; + long long p_tasks_runtimesum; //private: uint32_t state; @@ -157,6 +159,7 @@ private slots: private: ListItems * m_listitems; Item * m_item; + bool m_inworklist; int m_blocknum; int m_jobid; diff --git a/afanasy/src/watch/ctrljobs.cpp b/afanasy/src/watch/ctrljobs.cpp index 863d9d700..062022bcd 100644 --- a/afanasy/src/watch/ctrljobs.cpp +++ b/afanasy/src/watch/ctrljobs.cpp @@ -27,8 +27,11 @@ CtrlJobs::CtrlJobs(QWidget * i_parent, ListJobs * i_listjobs, bool i_inworklist) setFrameShadow(QFrame::Raised); QHBoxLayout * layout = new QHBoxLayout(this); + layout->setSizeConstraint(QLayout::SetMaximumSize); - layout->addWidget(new QLabel("Thumbs:", this)); + QLabel * lThumbs = new QLabel("Thumbs:", this); + lThumbs->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); + layout->addWidget(lThumbs); for (int i = 0; i < ms_thumbs_names.size(); i++) { @@ -50,6 +53,24 @@ CtrlJobs::CtrlJobs(QWidget * i_parent, ListJobs * i_listjobs, bool i_inworklist) m_thumbs_btns.append(btn); } + QLabel * lMax = new QLabel("Max(hrs):", this); + lMax->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); + lMax->setToolTip("Mark job blocks with tasks maximum running time above this value."); + layout->addWidget(lMax); + + m_max_runtime_edit = new QLineEdit(this); + QDoubleValidator * dv = new QDoubleValidator(0, 24*10, 2, m_max_runtime_edit); + dv->setNotation(QDoubleValidator::StandardNotation); + m_max_runtime_edit->setValidator(dv); + m_max_runtime_edit->setFixedWidth(32); + connect(m_max_runtime_edit, SIGNAL(editingFinished()), this, SLOT(slot_MaxEditingFinished())); + layout->addWidget(m_max_runtime_edit); + int seconds = afqt::QEnvironment::jobs_run_time_max_secs.n; + if (m_inworklist) + seconds = afqt::QEnvironment::work_run_time_max_secs.n; + if (seconds) + m_max_runtime_edit->setText(QString::number(double(seconds) / 60.0 / 60.0, 'f', 2)); + CtrlJobsViewOptions * viewOpts = new CtrlJobsViewOptions(this, m_listjobs, m_inworklist); layout->addWidget(viewOpts); } @@ -88,11 +109,28 @@ void CtrlJobs::slot_ThumsButtonClicked(Button * i_btn) m_listjobs->jobsHeightRecalculate(); } +void CtrlJobs::slot_MaxEditingFinished() +{ + QString text = m_max_runtime_edit->text(); + double hours = text.toDouble(); + if (hours <= 0) + m_max_runtime_edit->clear(); + int seconds = int(hours * 60 * 60); + if (seconds < 0) + seconds = 0; + if (m_inworklist) + afqt::QEnvironment::work_run_time_max_secs.n = seconds; + else + afqt::QEnvironment::jobs_run_time_max_secs.n = seconds; + m_listjobs->repaintItems(); +} + CtrlJobsViewOptions::CtrlJobsViewOptions(QWidget * i_parent, ListJobs * i_listjobs, bool i_inworklist): QLabel("View Options", i_parent), m_listjobs(i_listjobs), m_inworklist(i_inworklist) { + setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); setFrameShape(QFrame::StyledPanel); setFrameShadow(QFrame::Raised); diff --git a/afanasy/src/watch/ctrljobs.h b/afanasy/src/watch/ctrljobs.h index ef9370dfe..efee01a73 100644 --- a/afanasy/src/watch/ctrljobs.h +++ b/afanasy/src/watch/ctrljobs.h @@ -18,12 +18,15 @@ Q_OBJECT private slots: void slot_ThumsButtonClicked(Button*); + void slot_MaxEditingFinished(); private: QList m_thumbs_btns; static const QStringList ms_thumbs_names; static const QList ms_thumbs_sizes; + QLineEdit * m_max_runtime_edit; + ListJobs * m_listjobs; const bool m_inworklist; }; diff --git a/afanasy/src/watch/itemjob.cpp b/afanasy/src/watch/itemjob.cpp index 035047c70..3a6da13cf 100644 --- a/afanasy/src/watch/itemjob.cpp +++ b/afanasy/src/watch/itemjob.cpp @@ -47,7 +47,7 @@ ItemJob::ItemJob(ListNodes * i_list_nodes, bool i_inworklist, af::Job * i_job, c for (int b = 0; b < i_job->getBlocksNum(); b++) { const af::BlockData * blockdata = i_job->getBlockData(b); - BlockInfo * blockinfo = new BlockInfo(blockdata, this, m_list_nodes); + BlockInfo * blockinfo = new BlockInfo(blockdata, this, m_list_nodes, m_inworklist); QObject::connect(blockinfo, SIGNAL(sig_BlockAction(int, QString)), m_list_nodes, SLOT(slot_BlockAction(int, QString))); m_blocks.append(blockinfo); } @@ -117,7 +117,7 @@ void ItemJob::v_updateValues(af::Node * i_afnode, int i_msgType) for (int b = m_blocks.size(); b < job->getBlocksNum(); b++) { const af::BlockData * blockdata = job->getBlockData(b); - BlockInfo * blockinfo = new BlockInfo(blockdata, this, m_list_nodes); + BlockInfo * blockinfo = new BlockInfo(blockdata, this, m_list_nodes, m_inworklist); QObject::connect(blockinfo, SIGNAL(sig_BlockAction(int, QString)), m_list_nodes, SLOT(slot_BlockAction(int, QString))); m_blocks.append(blockinfo); }