From d5d6b32787751f93af7e86ff4372200a4b8d67cb Mon Sep 17 00:00:00 2001 From: Matthew Budd Date: Fri, 27 Nov 2020 23:42:32 -0500 Subject: [PATCH] Added GUI scheduling parameters to Qt timing config window --- src/drivers/Qt/ConsoleWindow.cpp | 253 ++++++++++++++++++++++++------- src/drivers/Qt/ConsoleWindow.h | 9 +- src/drivers/Qt/TimingConf.cpp | 153 ++++++++++++++++++- src/drivers/Qt/TimingConf.h | 7 + 4 files changed, 366 insertions(+), 56 deletions(-) diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index 4cd8a8f6..d62bd326 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -1800,81 +1800,226 @@ void consoleWin_t::aboutQt(void) return; } -void consoleWin_t::setPriority( QThread::Priority priority_req ) +int consoleWin_t::setNicePriority( int value ) { + int ret = 0; +#if defined(__linux__) + + if ( value < -20 ) + { + value = -20; + } + else if ( value > 19 ) + { + value = 19; + } + + if ( ::setpriority( PRIO_PROCESS, getpid(), value ) ) + { + perror("Emulator thread setpriority error: "); + ret = -1; + } +#elif defined(__APPLE__) + + if ( value < -20 ) + { + value = -20; + } + else if ( value > 20 ) + { + value = 20; + } + + if ( ::setpriority( PRIO_PROCESS, getpid(), value ) ) + { + perror("Emulator thread setpriority error: "); + ret = -1; + } +#endif + return ret; +} + +int consoleWin_t::getNicePriority(void) +{ + return ::getpriority( PRIO_PROCESS, getpid() ); +} + +int consoleWin_t::getMinSchedPriority(void) +{ + int policy, prio; + + if ( getSchedParam( policy, prio ) ) + { + return 0; + } + return sched_get_priority_min( policy ); +} + +int consoleWin_t::getMaxSchedPriority(void) +{ + int policy, prio; + + if ( getSchedParam( policy, prio ) ) + { + return 0; + } + return sched_get_priority_max( policy ); +} + +int consoleWin_t::getSchedParam( int &policy, int &priority ) +{ + int ret = 0; + +#if defined(__linux__) + struct sched_param p; + + policy = sched_getscheduler( getpid() ); + + if ( sched_getparam( getpid(), &p ) ) + { + ret = -1; + } + + priority = p.sched_priority; + +#elif defined(__APPLE__) + struct sched_param p; + + if ( pthread_getschedparam( pself, &policy, &p ) ) + { + perror("GUI thread pthread_getschedparam error: "); + ret = -1; + } +#endif + return ret; +} + +int consoleWin_t::setSchedParam( int policy, int priority ) +{ + int ret = 0; #if defined(__linux__) struct sched_param p; int minPrio, maxPrio; - minPrio = sched_get_priority_min( SCHED_FIFO ); - maxPrio = sched_get_priority_max( SCHED_FIFO ); + minPrio = sched_get_priority_min( policy ); + maxPrio = sched_get_priority_max( policy ); - p.sched_priority = maxPrio; - - if ( ::setpriority( PRIO_PROCESS, getpid(), -20 ) ) + if ( priority < minPrio ) { - perror("Qt Window thread setpriority error: "); + priority = minPrio; } - printf("sched_getscheduler(): %i \n", sched_getscheduler( getpid() ) ); - printf("sched_get_priority_min(SCHED_FIFO): %i \n", minPrio ); - printf("sched_get_priority_max(SCHED_FIFO): %i \n", maxPrio ); - - printf("setpriority(): %i \n", ::getpriority( PRIO_PROCESS, getpid() ) ); - - if ( sched_setscheduler( getpid(), SCHED_FIFO, &p ) ) + else if ( priority > maxPrio ) { - perror("Qt Window thread sched_setscheduler error:"); + priority = maxPrio; } - printf("sched_getscheduler(): %i \n", sched_getscheduler( getpid() ) ); + p.sched_priority = priority; + if ( sched_setscheduler( getpid(), policy, &p ) ) + { + perror("GUI thread sched_setscheduler error"); + ret = -1; + } #elif defined(__APPLE__) - struct sched_param p; - int oldPolicy, newPolicy, minPrio, maxPrio; - QThread *qself; - pthread_t self; + int minPrio, maxPrio; - qself = QThread::currentThread(); + minPrio = sched_get_priority_min( policy ); + maxPrio = sched_get_priority_max( policy ); - self = pthread_self(); - newPolicy = SCHED_FIFO; - - printf("QThreadID: %p \n", QThread::currentThreadId() ); - printf("PThreadID: %p \n", self ); - - minPrio = sched_get_priority_min( SCHED_FIFO ); - maxPrio = sched_get_priority_max( SCHED_FIFO ); - - pthread_getschedparam( self, &oldPolicy, &p ); - - printf("GUI pthread_getschedparam(): %i, %i \n", oldPolicy, p.sched_priority ); - - qself->setPriority( priority_req ); - - p.sched_priority = maxPrio; - - //if ( ::pthread_setschedparam( self, newPolicy, &p ) != 0 ) - //{ - //perror("GUI thread pthread_setschedparam error: "); - //} - pthread_getschedparam( self, &oldPolicy, &p ); - - printf("GUI pthread_getschedparam(): %i, %i \n", oldPolicy, p.sched_priority ); - - if ( ::setpriority( PRIO_PROCESS, getpid(), -20 ) ) + if ( priority < minPrio ) { - perror("GUI thread setpriority error: "); + priority = minPrio; } - printf("GUI Thread setpriority(): %i \n", ::getpriority( PRIO_PROCESS, getpid() ) ); -#else - QThread *mainThread; + else if ( priority > maxPrio ) + { + priority = maxPrio; + } + p.sched_priority = priority; - mainThread = QThread::currentThread(); - - mainThread->setPriority( priority_req ); + if ( ::pthread_setschedparam( pself, policy, &p ) != 0 ) + { + perror("GUI thread pthread_setschedparam error: "); + } #endif + return ret; } + +//void consoleWin_t::setPriority( QThread::Priority priority_req ) +//{ +//#if defined(__linux__) +// struct sched_param p; +// int minPrio, maxPrio; +// +// minPrio = sched_get_priority_min( SCHED_FIFO ); +// maxPrio = sched_get_priority_max( SCHED_FIFO ); +// +// p.sched_priority = maxPrio; +// +// if ( ::setpriority( PRIO_PROCESS, getpid(), -20 ) ) +// { +// perror("Qt Window thread setpriority error "); +// } +// printf("sched_getscheduler(): %i \n", sched_getscheduler( getpid() ) ); +// printf("sched_get_priority_min(SCHED_FIFO): %i \n", minPrio ); +// printf("sched_get_priority_max(SCHED_FIFO): %i \n", maxPrio ); +// +// printf("setpriority(): %i \n", ::getpriority( PRIO_PROCESS, getpid() ) ); +// +// if ( sched_setscheduler( getpid(), SCHED_FIFO, &p ) ) +// { +// perror("Qt Window thread sched_setscheduler error:"); +// } +// printf("sched_getscheduler(): %i \n", sched_getscheduler( getpid() ) ); +// +//#elif defined(__APPLE__) +// +// struct sched_param p; +// int oldPolicy, newPolicy, minPrio, maxPrio; +// QThread *qself; +// pthread_t self; +// +// qself = QThread::currentThread(); +// +// self = pthread_self(); +// newPolicy = SCHED_FIFO; +// +// printf("QThreadID: %p \n", QThread::currentThreadId() ); +// printf("PThreadID: %p \n", self ); +// +// minPrio = sched_get_priority_min( SCHED_FIFO ); +// maxPrio = sched_get_priority_max( SCHED_FIFO ); +// +// pthread_getschedparam( self, &oldPolicy, &p ); +// +// printf("GUI pthread_getschedparam(): %i, %i \n", oldPolicy, p.sched_priority ); +// +// qself->setPriority( priority_req ); +// +// p.sched_priority = maxPrio; +// +// //if ( ::pthread_setschedparam( self, newPolicy, &p ) != 0 ) +// //{ +// //perror("GUI thread pthread_setschedparam error: "); +// //} +// pthread_getschedparam( self, &oldPolicy, &p ); +// +// printf("GUI pthread_getschedparam(): %i, %i \n", oldPolicy, p.sched_priority ); +// +// if ( ::setpriority( PRIO_PROCESS, getpid(), -20 ) ) +// { +// perror("GUI thread setpriority error: "); +// } +// printf("GUI Thread setpriority(): %i \n", ::getpriority( PRIO_PROCESS, getpid() ) ); +//#else +// QThread *mainThread; +// +// mainThread = QThread::currentThread(); +// +// mainThread->setPriority( priority_req ); +//#endif +//} + void consoleWin_t::syncActionConfig( QAction *act, const char *property ) { if ( act->isCheckable() ) diff --git a/src/drivers/Qt/ConsoleWindow.h b/src/drivers/Qt/ConsoleWindow.h index 88b9e631..971f2c85 100644 --- a/src/drivers/Qt/ConsoleWindow.h +++ b/src/drivers/Qt/ConsoleWindow.h @@ -75,7 +75,14 @@ class consoleWin_t : public QMainWindow int showListSelectDialog( const char *title, std::vector &l ); - void setPriority( QThread::Priority priority_req ); + #if defined(__linux__) || defined(__APPLE__) + int setSchedParam( int policy, int priority ); + int getSchedParam( int &policy, int &priority ); + int setNicePriority( int value ); + int getNicePriority( void ); + int getMinSchedPriority(void); + int getMaxSchedPriority(void); + #endif emulatorThread_t *emulatorThread; diff --git a/src/drivers/Qt/TimingConf.cpp b/src/drivers/Qt/TimingConf.cpp index fa039e31..58e9cd38 100644 --- a/src/drivers/Qt/TimingConf.cpp +++ b/src/drivers/Qt/TimingConf.cpp @@ -25,7 +25,7 @@ TimingConfDialog_t::TimingConfDialog_t(QWidget *parent) QVBoxLayout *mainLayout, *vbox; //QHBoxLayout *hbox; QGridLayout *grid; - QGroupBox *emuPrioBox; + QGroupBox *emuPrioBox, *guiPrioBox; setWindowTitle("Timing Configuration"); @@ -34,6 +34,7 @@ TimingConfDialog_t::TimingConfDialog_t(QWidget *parent) emuPrioCtlEna = new QCheckBox( tr("Set Scheduling Parameters at Startup") ); emuPrioBox = new QGroupBox( tr("EMU Thread Scheduling Parameters") ); + guiPrioBox = new QGroupBox( tr("GUI Thread Scheduling Parameters") ); grid = new QGridLayout(); emuPrioBox->setLayout( grid ); @@ -56,6 +57,27 @@ TimingConfDialog_t::TimingConfDialog_t(QWidget *parent) mainLayout->addWidget( emuPrioCtlEna ); mainLayout->addWidget( emuPrioBox ); + grid = new QGridLayout(); + guiPrioBox->setLayout( grid ); + + guiSchedPolicyBox = new QComboBox(); + guiSchedPrioSlider = new QSlider( Qt::Horizontal ); + guiSchedNiceSlider = new QSlider( Qt::Horizontal ); + guiSchedPrioLabel = new QLabel( tr("Priority (RT)") ); + + guiSchedPolicyBox->addItem( tr("SCHED_OTHER") , SCHED_OTHER ); + guiSchedPolicyBox->addItem( tr("SCHED_FIFO") , SCHED_FIFO ); + guiSchedPolicyBox->addItem( tr("SCHED_RR") , SCHED_RR ); + + grid->addWidget( new QLabel( tr("Policy") ), 0, 0 ); + grid->addWidget( guiSchedPolicyBox, 0, 1 ); + grid->addWidget( guiSchedPrioLabel, 1, 0 ); + grid->addWidget( guiSchedPrioSlider, 1, 1 ); + grid->addWidget( new QLabel( tr("Priority (Nice)") ), 2, 0 ); + grid->addWidget( guiSchedNiceSlider, 2, 1 ); + + mainLayout->addWidget( guiPrioBox ); + setLayout( mainLayout ); updatePolicyBox(); @@ -65,6 +87,9 @@ TimingConfDialog_t::TimingConfDialog_t(QWidget *parent) connect( emuSchedPolicyBox , SIGNAL(activated(int)) , this, SLOT(emuSchedPolicyChange(int)) ); connect( emuSchedNiceSlider , SIGNAL(valueChanged(int)), this, SLOT(emuSchedNiceChange(int)) ); connect( emuSchedPrioSlider , SIGNAL(valueChanged(int)), this, SLOT(emuSchedPrioChange(int)) ); + connect( guiSchedPolicyBox , SIGNAL(activated(int)) , this, SLOT(guiSchedPolicyChange(int)) ); + connect( guiSchedNiceSlider , SIGNAL(valueChanged(int)), this, SLOT(guiSchedNiceChange(int)) ); + connect( guiSchedPrioSlider , SIGNAL(valueChanged(int)), this, SLOT(guiSchedPrioChange(int)) ); } //---------------------------------------------------------------------------- TimingConfDialog_t::~TimingConfDialog_t(void) @@ -181,6 +206,100 @@ void TimingConfDialog_t::emuSchedPolicyChange( int index ) fceuWrapperUnLock(); } //---------------------------------------------------------------------------- +void TimingConfDialog_t::guiSchedNiceChange(int val) +{ + if ( consoleWindow == NULL ) + { + return; + } + fceuWrapperLock(); + if ( consoleWindow->setNicePriority( -val ) ) + { + char msg[1024]; + + sprintf( msg, "Error: system call setPriority Failed\nReason: %s\n", strerror(errno) ); +#ifdef __linux__ + strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n"); + strcat( msg, " /etc/security/limits.conf \n\n"); + strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n"); + strcat( msg, "* - priority 99 \n"); + strcat( msg, "* - rtprio 99 \n"); + strcat( msg, "* - nice -20 \n"); +#endif + printf("%s\n", msg ); + consoleWindow->QueueErrorMsgWindow( msg ); + updateSliderValues(); + } + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +void TimingConfDialog_t::guiSchedPrioChange(int val) +{ + int policy, prio; + + if ( consoleWindow == NULL ) + { + return; + } + fceuWrapperLock(); + consoleWindow->getSchedParam( policy, prio ); + + if ( consoleWindow->setSchedParam( policy, val ) ) + { + char msg[1024]; + + sprintf( msg, "Error: system call pthread_setschedparam Failed\nReason: %s\n", strerror(errno) ); +#ifdef __linux__ + strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n"); + strcat( msg, " /etc/security/limits.conf \n\n"); + strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n"); + strcat( msg, "* - priority 99 \n"); + strcat( msg, "* - rtprio 99 \n"); + strcat( msg, "* - nice -20 \n"); +#endif + printf("%s\n", msg ); + consoleWindow->QueueErrorMsgWindow( msg ); + updateSliderValues(); + } + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- +void TimingConfDialog_t::guiSchedPolicyChange( int index ) +{ + int policy, prio; + + if ( consoleWindow == NULL ) + { + return; + } + fceuWrapperLock(); + consoleWindow->getSchedParam( policy, prio ); + + policy = guiSchedPolicyBox->itemData( index ).toInt(); + + if ( consoleWindow->setSchedParam( policy, prio ) ) + { + char msg[1024]; + + sprintf( msg, "Error: system call pthread_setschedparam Failed\nReason: %s\n", strerror(errno) ); +#ifdef __linux__ + strcat( msg, "Ensure that your system has the proper resource permissions set in the file:\n\n"); + strcat( msg, " /etc/security/limits.conf \n\n"); + strcat( msg, "Adding the following lines to that file and rebooting will usually fix the issue:\n\n"); + strcat( msg, "* - priority 99 \n"); + strcat( msg, "* - rtprio 99 \n"); + strcat( msg, "* - nice -20 \n"); +#endif + printf("%s\n", msg ); + consoleWindow->QueueErrorMsgWindow( msg ); + } + + updatePolicyBox(); + updateSliderLimits(); + updateSliderValues(); + fceuWrapperUnLock(); +} +//---------------------------------------------------------------------------- void TimingConfDialog_t::updatePolicyBox(void) { int policy, prio; @@ -200,6 +319,17 @@ void TimingConfDialog_t::updatePolicyBox(void) } } + consoleWindow->getSchedParam( policy, prio ); + + for (int j=0; jcount(); j++) + { + if ( guiSchedPolicyBox->itemData(j).toInt() == policy ) + { + //printf("Found Policy %i %i\n", j , policy ); + guiSchedPolicyBox->setCurrentIndex( j ); + } + } + } //---------------------------------------------------------------------------- void TimingConfDialog_t::updateSliderValues(void) @@ -225,6 +355,22 @@ void TimingConfDialog_t::updateSliderValues(void) emuSchedPrioLabel->setEnabled(false); emuSchedPrioSlider->setEnabled(false); } + + consoleWindow->getSchedParam( policy, prio ); + + guiSchedNiceSlider->setValue( -consoleWindow->getNicePriority() ); + guiSchedPrioSlider->setValue( prio ); + + if ( (policy == SCHED_RR) || (policy == SCHED_FIFO) ) + { + guiSchedPrioLabel->setEnabled(true); + guiSchedPrioSlider->setEnabled(true); + } + else + { + guiSchedPrioLabel->setEnabled(false); + guiSchedPrioSlider->setEnabled(false); + } } //---------------------------------------------------------------------------- void TimingConfDialog_t::updateSliderLimits(void) @@ -239,5 +385,10 @@ void TimingConfDialog_t::updateSliderLimits(void) emuSchedPrioSlider->setMinimum( consoleWindow->emulatorThread->getMinSchedPriority() ); emuSchedPrioSlider->setMaximum( consoleWindow->emulatorThread->getMaxSchedPriority() ); + guiSchedNiceSlider->setMinimum( -20 ); + guiSchedNiceSlider->setMaximum( 20 ); + guiSchedPrioSlider->setMinimum( consoleWindow->getMinSchedPriority() ); + guiSchedPrioSlider->setMaximum( consoleWindow->getMaxSchedPriority() ); + } //---------------------------------------------------------------------------- diff --git a/src/drivers/Qt/TimingConf.h b/src/drivers/Qt/TimingConf.h index d6d8a23b..ec80908a 100644 --- a/src/drivers/Qt/TimingConf.h +++ b/src/drivers/Qt/TimingConf.h @@ -35,6 +35,10 @@ class TimingConfDialog_t : public QDialog QSlider *emuSchedPrioSlider; QSlider *emuSchedNiceSlider; QLabel *emuSchedPrioLabel; + QComboBox *guiSchedPolicyBox; + QSlider *guiSchedPrioSlider; + QSlider *guiSchedNiceSlider; + QLabel *guiSchedPrioLabel; private: void updatePolicyBox(void); @@ -47,5 +51,8 @@ class TimingConfDialog_t : public QDialog void emuSchedNiceChange( int val ); void emuSchedPrioChange( int val ); void emuSchedPolicyChange( int index ); + void guiSchedNiceChange( int val ); + void guiSchedPrioChange( int val ); + void guiSchedPolicyChange( int index ); };