2018-08-22 11:29:39 +02:00
/** Linux specific real-time optimizations
*
* @ author Steffen Vogel < stvogel @ eonerc . rwth - aachen . de >
2020-01-20 17:15:25 +01:00
* @ copyright 2014 - 2020 , 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>
2018-08-22 11:29:39 +02:00
# include <villas/config.h>
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
# include <villas/kernel/kernel.h>
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__
int is_rt ;
/* 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
if ( affinity )
2018-08-27 11:12:40 +02:00
setAffinity ( 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__
2019-02-12 17:28:37 +01:00
void setAffinity ( int affinity )
2018-08-22 11:29:39 +02:00
{
char isolcpus [ 255 ] ;
int is_isol , ret ;
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
is_isol = kernel_get_cmdline_param ( " isolcpus " , isolcpus , sizeof ( isolcpus ) ) ;
2019-04-15 13:01:01 +02:00
if ( is_isol )
2018-08-27 11:12:40 +02:00
logger - > warn ( " You should reserve some cores for " PROJECT_NAME " (see 'isolcpus') " ) ;
2018-08-22 11:29:39 +02:00
else {
2019-04-15 13:01:01 +02:00
CpuSet cset_isol ( isolcpus ) ;
CpuSet cset_non_isol = ~ cset_isol & cset_pin ;
2018-08-22 11:29:39 +02:00
2018-08-27 11:12:40 +02:00
if ( cset_non_isol . count ( ) > 0 )
2019-04-15 13:01:01 +02:00
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 ) ;
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 )
2019-04-15 13:01:01 +02:00
throw SystemError ( " Failed to set CPU affinity to cores: {} " , ( std : : string ) cset_pin ) ;
2018-08-22 11:29:39 +02:00
2019-04-15 13:01:01 +02:00
logger - > debug ( " Set affinity to cores: {} " , ( std : : string ) cset_pin ) ;
2018-08-22 11:29:39 +02:00
}
2019-02-12 17:28:37 +01:00
void setPriority ( int priority )
2018-08-22 11:29:39 +02:00
{
int ret ;
struct sched_param param = {
. sched_priority = priority
} ;
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 */