2018-08-22 11:29:39 +02:00
/** Linux specific real-time optimizations
*
2022-03-15 09:13:39 -04:00
* @ author Steffen Vogel < svogel2 @ eonerc . rwth - aachen . de >
2022-03-15 09:05:42 -04:00
* @ copyright 2014 - 2022 , Institute for Automation of Complex Power Systems , EONERC
2022-05-19 17:40:10 +02:00
* @ license Apache License 2.0
2018-08-22 11:29:39 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# 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 ;
2022-12-02 17:16:44 +01:00
# 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
2022-12-02 17:16:44 +01: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 ;
2022-12-02 17:16:44 +01: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 " ) ;
2022-12-02 17:16:44 +01: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
}
2022-12-02 17:16:44 +01:00
# endif // __linux__
2018-08-27 11:12:40 +02:00
2022-12-02 17:16:44 +01:00
} // namespace villas
} // namespace kernel
} // namespace rt