2018-08-22 11:29:39 +02:00
/** Linux specific real-time optimizations
*
* @ author Steffen Vogel < stvogel @ eonerc . rwth - aachen . de >
2021-06-21 16:09:11 -04:00
* @ copyright 2014 - 2021 , Institute for Automation of Complex Power Systems , EONERC
2018-08-22 11:29:39 +02:00
* @ license GNU General Public License ( version 3 )
*
* VILLAScommon
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <sched.h>
# include <unistd.h>
2018-08-27 11:12:40 +02:00
# include <villas/log.hpp>
# include <villas/cpuset.hpp>
2021-08-11 12:40:19 -04:00
# include <villas/config.hpp>
2019-04-23 12:57:51 +02:00
# include <villas/utils.hpp>
2018-08-27 11:12:40 +02:00
# include <villas/exceptions.hpp>
2018-08-22 11:29:39 +02:00
2019-10-27 20:23:47 +01:00
# include <villas/kernel/kernel.hpp>
2018-08-27 11:12:40 +02:00
# include <villas/kernel/kernel.hpp>
# include <villas/kernel/rt.hpp>
2018-08-22 11:29:39 +02:00
2018-10-19 16:32:44 +02:00
# ifdef __linux__
using villas : : utils : : CpuSet ;
# endif /* __linux__ */
2018-08-27 11:12:40 +02:00
namespace villas {
namespace kernel {
namespace rt {
2019-02-12 17:28:37 +01:00
void init ( int priority , int affinity )
2018-08-22 11:29:39 +02:00
{
2019-01-21 16:32:42 +01:00
Logger logger = logging . get ( " kernel:rt " ) ;
2018-11-01 14:31:41 +01:00
logger - > info ( " Initialize sub-system " ) ;
2018-08-22 11:29:39 +02:00
# ifdef __linux__
2020-09-13 08:35:27 +02:00
int is_rt , is_isol ;
char isolcpus [ 255 ] ;
2018-08-22 11:29:39 +02:00
/* Use FIFO scheduler with real time priority */
2018-08-27 11:12:40 +02:00
is_rt = isPreemptible ( ) ;
2019-02-12 17:28:37 +01:00
if ( ! is_rt )
2018-08-27 11:12:40 +02:00
logger - > warn ( " We recommend to use an PREEMPT_RT patched kernel! " ) ;
2018-08-22 11:29:39 +02:00
if ( priority )
2018-08-27 11:12:40 +02:00
setPriority ( priority ) ;
2018-08-22 11:29:39 +02:00
else
2018-08-27 11:12:40 +02:00
logger - > warn ( " You might want to use the 'priority' setting to increase " PROJECT_NAME " 's process priority " ) ;
2018-08-22 11:29:39 +02:00
2020-09-13 08:35:27 +02:00
if ( affinity ) {
2021-05-20 06:08:12 -04:00
is_isol = getCmdlineParam ( " isolcpus " , isolcpus , sizeof ( isolcpus ) ) ;
2020-09-13 08:35:27 +02:00
if ( is_isol )
logger - > warn ( " You should reserve some cores for " PROJECT_NAME " (see 'isolcpus') " ) ;
else {
CpuSet cset_pin ( affinity ) ;
CpuSet cset_isol ( isolcpus ) ;
CpuSet cset_non_isol = ~ cset_isol & cset_pin ;
if ( cset_non_isol . count ( ) > 0 )
logger - > warn ( " Affinity setting includes cores which are not isolated: affinity={}, isolcpus={}, non_isolated={} " , ( std : : string ) cset_pin , ( std : : string ) cset_isol , ( std : : string ) cset_non_isol ) ;
}
setProcessAffinity ( affinity ) ;
}
2018-08-22 11:29:39 +02:00
else
2018-08-27 11:12:40 +02:00
logger - > warn ( " You might want to use the 'affinity' setting to pin " PROJECT_NAME " to dedicate CPU cores " ) ;
2018-08-22 11:29:39 +02:00
# else
2018-08-27 11:12:40 +02:00
logger - > warn ( " This platform is not optimized for real-time execution " ) ;
2019-02-12 17:28:37 +01:00
2018-10-19 16:32:44 +02:00
( void ) affinity ;
( void ) priority ;
2019-04-05 03:39:32 +02:00
# endif /* __linux__ */
2018-08-22 11:29:39 +02:00
}
# ifdef __linux__
2020-09-13 08:35:27 +02:00
void setProcessAffinity ( int affinity )
2018-08-22 11:29:39 +02:00
{
2020-09-13 08:35:27 +02:00
int ret ;
2018-08-22 11:29:39 +02:00
2020-09-13 10:59:19 +02:00
assert ( affinity ! = 0 ) ;
2019-01-21 16:32:42 +01:00
Logger logger = logging . get ( " kernel:rt " ) ;
2018-08-22 11:29:39 +02:00
/* Pin threads to CPUs by setting the affinity */
2019-04-15 13:01:01 +02:00
CpuSet cset_pin ( affinity ) ;
2018-08-22 11:29:39 +02:00
2018-08-27 11:12:40 +02:00
ret = sched_setaffinity ( 0 , cset_pin . size ( ) , cset_pin ) ;
2018-08-22 11:29:39 +02:00
if ( ret )
2020-09-13 10:59:19 +02:00
throw SystemError ( " Failed to set CPU affinity of process " ) ;
2018-08-22 11:29:39 +02:00
2020-09-13 10:59:19 +02:00
logger - > debug ( " Set affinity to {} {} " , cset_pin . count ( ) = = 1 ? " core " : " cores " , ( std : : string ) cset_pin ) ;
2018-08-22 11:29:39 +02:00
}
2020-09-13 08:35:27 +02:00
void setThreadAffinity ( pthread_t thread , int affinity )
{
int ret ;
2020-09-13 10:59:19 +02:00
assert ( affinity ! = 0 ) ;
2020-09-13 08:35:27 +02:00
Logger logger = logging . get ( " kernel:rt " ) ;
CpuSet cset_pin ( affinity ) ;
ret = pthread_setaffinity_np ( thread , cset_pin . size ( ) , cset_pin ) ;
if ( ret )
2020-09-13 10:59:19 +02:00
throw SystemError ( " Failed to set CPU affinity of thread " ) ;
2020-09-13 08:35:27 +02:00
2020-09-13 10:59:19 +02:00
logger - > debug ( " Set affinity of thread {} to {} {} " , ( long unsigned ) thread , cset_pin . count ( ) = = 1 ? " core " : " cores " , ( std : : string ) cset_pin ) ;
2020-09-13 08:35:27 +02:00
}
2019-02-12 17:28:37 +01:00
void setPriority ( int priority )
2018-08-22 11:29:39 +02:00
{
int ret ;
2020-11-11 21:23:29 +01:00
struct sched_param param ;
param . sched_priority = priority ;
2018-08-22 11:29:39 +02:00
2019-01-21 16:32:42 +01:00
Logger logger = logging . get ( " kernel:rt " ) ;
2018-08-22 11:29:39 +02:00
ret = sched_setscheduler ( 0 , SCHED_FIFO , & param ) ;
if ( ret )
2018-12-02 02:47:55 +01:00
throw SystemError ( " Failed to set real time priority " ) ;
2018-08-22 11:29:39 +02:00
2018-08-27 11:12:40 +02:00
logger - > debug ( " Task priority set to {} " , priority ) ;
2018-08-22 11:29:39 +02:00
}
2019-02-12 17:28:37 +01:00
bool isPreemptible ( )
2018-08-22 11:29:39 +02:00
{
2019-02-12 17:28:37 +01:00
return access ( SYSFS_PATH " /kernel/realtime " , R_OK ) = = 0 ;
2018-08-22 11:29:39 +02:00
}
# endif /* __linux__ */
2018-08-27 11:12:40 +02:00
2019-03-26 06:50:56 +01:00
} /* namespace villas */
} /* namespace kernel */
} /* namespace rt */