一、编译安装方法
1. 编译安装环境
(1)Linux 操作系统
(2)EPICS BASE 3.15 (3.15.1 or later)
(MCoreUtils中使用了一些EPICS BASE 3.15之后才有的函数,例如epicsThreadHookAdd()函数)
2. 下载安装包
https://github.com/epics-modules/MCoreUtils
3. 编译安装生成mcoreutils库
tar -zxvf MCoreUtils-1.2.2.tar.gz /home/dongxw/modules/MCoreUtils-1.2.2
cd /home/dongxw/modules/MCoreUtils-1.2.2
make
二、使用方法
1. 在IOC中引入MCoreUtils
(1)在< path to IOC >/configure/RELEASE文件中,添加MCoreUtils路径:
MCOREUTILS = /home/dongxw/modules/MCoreUtils-1.2.2
(2)在< path to IOC >/< IOC >APP/src/Makefile文件中,添加MCoreUtils库和dbd:
...
<IOC>_DBD += mcoreutils.dbd
...
<IOC>_LIBS += mcoreutils
...
(3)编译运行IOC
注意:MCoreUtils 仅适用于Linux系统,因此只有Linux下编译运行的IOC可以执行上述操作,从而使用MCoreUtils。
2. 在文件中定义线程规则
可以预先设置线程规则文件:
(1) /etc/rtrules文件
(2)$HOME下的EPICS_MCORE_USERCONFIG定义的文件名或.rtrules文件
文件中线程规则定义格式为:
name:policy:priority:affinity:pattern
通过epicsThreadOnce()1和 epicsThreadHookAdd()函数2,在任何epicsThreadOnce()函数之前完成以下操作:读取线程规则文件后,生成threadRules表;令每个线程运行前都根据threadRules表中与id名字对应的规则修改id的线程规则。
3. 执行iocsh命令对线程规则进行操作
shellCommands.c 和 mcoreutils.dbd 文件结合,将一些函数注册为可在iocsh下执行的命令。这些命令在IOC启动时即注册入可执行命令库3,可以在 st.cmd 文件中执行这些命令,也可在 “epics>”命令行执行这些命令。
例如,IOC启动后,在iocsh下查看可执行命令库:
epics> help
...
iocRun iocshCmd iocshLoad iocshRun mcoreMLock
mcoreMUnlock mcoreThreadModify mcoreThreadRuleAdd
mcoreThreadRuleDelete mcoreThreadRulesShow
mcoreThreadShow mcoreThreadShowAll on pft
...
可以看到,关于 MCoreUtils 的一些命令也在其中。
例如,使用mcoreThreadShow命令来查看errlog线程的当前优先级状态:
epics> mcoreThreadShow errlog
mcoreThreadShow errlog
NAME EPICS ID LWP ID OSIPRI OSSPRI STATE POLICY CPUSET
errlog 0x73f480 15427 10 0 OK OTHER 0-3
也可以更改一些线程的优先级:
epics> mcoreThreadShow scan-10
mcoreThreadShow scan-10
NAME EPICS ID LWP ID OSIPRI OSSPRI STATE POLICY CPUSET
scan-10 0x8c4db0 15443 50 0 OK OTHER 0-3
epics> mcoreThreadModify scan-10 * 40 0 # 更改OSIPRI为40,CPU亲和性为0号CPU
mcoreThreadModify scan-10 * 40 0
epics> mcoreThreadShow scan-10
mcoreThreadShow scan-10
NAME EPICS ID LWP ID OSIPRI OSSPRI STATE POLICY CPUSET
scan-10 0x8c4db0 15443 40 0 OK OTHER 0
三、多核运行测试
编写脚本对IOC多线程的多核运行情况进行测试:
#!/bin/bash
# this script can have one or two inputs:
# $1 is for the name of IOC
# $2 is whether or not to use MCoreUtils. If not, input $2 as "no". If yes, no need to input anything as $2.
ioc=$1
using_mcu=$2
pid=`ps -ef|grep st.cmd|grep $ioc | awk '{print $2}'`
file=`[ ${using_mcu} ] && echo ${using_mcu}_`multicore.log
echo "${ioc}'s pid is:$pid \nwritting into $file"
ps -o pid,tid,psr -p $pid -m > $file
attend_psr()
{
psr=$@
line=1
for ppsr in $psr
do
if [ $ppsr != "PSR" ]
then
ppsr=" $ppsr" # 列对齐
fi
sed -i ''"$line"' s@$@ '"$ppsr"'@g' $file # 在每行末尾添加新数据
line=$((line+1))
done
}
while [ 1 ]
do
sleep 1
psr=`ps -o psr -p $pid -m` # 查询IOC多核运行情况
attend_psr $psr # 在log文件中新增一列数据
done
【参考文章】
Linux上如何查看某个进程的线程
Shell ps常用组合查看线程命令
判断Linux进程在哪个CPU核运行的方法
Linux多线程之pthread_setschedparam
C语言–Linux多线程pthread
如何获取进程的线程id?------说说gettid与pthread_self的区别
CPU亲和性(affinity)sched_setaffinity() 和 sched_getaffinity() CPU_SET()与CPU_ZERO()
linux进程、线程与cpu的亲和性(affinity)
sed在shell脚本中引用变量
sed命令简介及在sed命令中使用变量的方法
linux 搜索一个字符串再哪个文件中
Linux在文件中查找字符串
C语言正则表达式详解 regcomp() regexec() regfree()用法详解
-
在epics用户手册中对 epicsThreadOnce 函数描述如下:
“This is used as follows:void myInitFunc(void * arg) { ... } epicsThreadOnceId onceFlag = EPICS_THREAD_ONCE_INIT; ... epicsThreadOnce(&onceFlag,myInitFunc,(void *)myParm);
For each unique epicsThreadOnceId, epicsThreadOnce guarantees
- myInitFunc is called only once.
- myInitFunc completes before any epicsThreadOnce call completes.
Note that myInitFunc must not call epicsThreadOnce with the same onceId.”
-
在epics用户手册中对 epicsThreadHookAdd 函数描述如下:
“Register a routine to be called by every new thread before the thread function gets run. Hook routines will often register a thread exit routine with epicsAtThreadExit to release thread-specific resources they have allocated.” ↩︎ -
这种函数注册机制在epics用户手册中描述如下:
“ 18.3.3 Registrar Command Registration
Commands are normally registered with the IOC shell in a registrar function. The application’s database description file
uses the registrar keyword to specify a function which will be called from the EPICS initialization code during the
application startup process. This function then calls iocshRegister to register its commands with the iocsh.
… ” ↩︎