DiamondLightSource / pythonSoftIOC

Embed an EPICS IOC in a Python process
Apache License 2.0
31 stars 9 forks source link

devIocStats: SYS_CPU_LOAD and IOC_CPU_LOAD values are incorrect #131

Closed duqiang closed 1 year ago

duqiang commented 1 year ago

When enabling softioc.devIocStats, the values of :SYS_CPU_LOAD and :IOC_CPU_LOAD are incorrect.

To reproduce, compose ioc.py based on tutorial:

from softioc import softioc, builder
import cothread

builder.SetDeviceName("MY-DEVICE-PREFIX")
ai = builder.aIn('AI', initial_value=5)
ao = builder.aOut('AO', initial_value=12.45, on_update=lambda v: ai.set(v))
builder.LoadDatabase()
softioc.devIocStats('my_ioc')
softioc.iocInit()

def update():
    while True:
        ai.set(ai.get() + 1)
        cothread.Sleep(1)
cothread.Spawn(update)
softioc.interactive_ioc(globals())

Result when running ioc.py:

Starting iocInit
############################################################################
## EPICS 7.0.6.1
## Rev. 7.0.6.99.2.0
############################################################################
iocRun: All initialization complete
Python 3.10.4 (main, Mar 31 2022, 08:41:55) [GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> dbpr('my_ioc:SYS_CPU_LOAD')
my_ioc:SYS_CPU_LOAD 0
AMSG:               ASG :               DESC: System CPU Load                   
DISA: 0             DISP: 0             DISV: 1             
NAME: my_ioc:SYS_CPU_LOAD               NAMSG:              RVAL: 0             
SEVR: MAJOR         STAT: HIHI          SVAL: 0             TPRO: 0             
VAL : 2442.3690941135
>>> dbpr('my_ioc:IOC_CPU_LOAD')
my_ioc:IOC_CPU_LOAD 0
AMSG:               ASG :               DESC: IOC CPU Load  DISA: 0             
DISP: 0             DISV: 1             NAME: my_ioc:IOC_CPU_LOAD               
NAMSG:              RVAL: 0             SEVR: NO_ALARM      STAT: NO_ALARM      
SVAL: 0             TPRO: 0             VAL : 20.0192856949861
>>> 

True cpu load is about 0.3 - 0.4%:

$ ps -p 4186753 -o %cpu,%mem 
%CPU %MEM
 0.3  0.1
$ head -n 1 /proc/stat
cpu  221105886 1802813 52192077 7864068116 1410091 0 1526417 0 0 0
AlexanderWells-diamond commented 1 year ago

Thank you for pointing this out. It looks like there's more broken PVs than just those ones. For example:

>>> dbpr("my_ioc:CPU_CNT")
AMSG:               ASG :               DESC: Number of CPUs                    
DISA: 0             DISV: 1             NAME: my_ioc:CPU_CNT                    
NAMSG:              RVAL: 0             SEVR: NO_ALARM      STAT: NO_ALARM      
SVAL: 0             TPRO: 0             VAL : 1  

As you can see, it looks like devIocStats is not correctly picking up the number of CPUs on my system (I have 4). This number is used in a lot of calculations, so is probably a/the source of the issue.

Looking at the devIocStatsOSD.h file, it seems there is a defaults version but there is no override header file for Linux. This means the number of CPUs defaults to 1, and is never adjusted.

(We use the Linux distribution as that's how we set up the build in setup.py - the OS_CLASS variable returns Linux)

I'm tempted to say this is an issue in devIocStats, although I'd probably have to do more investigation to prove that.

coretl commented 1 year ago

I think something in the EPICS build system will pick up the posix version too, which we are not currently pulling into the build.

This file would appear to give the right CPU count: https://github.com/epics-modules/iocStats/blob/fa12cb2172e3477debd1372f57e68d2ae21f7c1b/devIocStats/os/posix/devIocStatsOSD.h#L42-L43

I think the best thing to do would be to build devIocStats once standalone and look at the gcc command it generates for Linux, which files it picks up, and replicate that in setup.py

coretl commented 1 year ago

Here's the gcc line from devIocStats:

/usr/bin/gcc  -D_GNU_SOURCE -D_DEFAULT_SOURCE          -D_X86_64_ -DUNIX  -Dlinux      -O3 -g   -Wall -Werror-implicit-function-declaration      -mtune=generic     -m64  -fPIC -I. -I../O.Common -I. -I. -I../os/Linux -I../os/posix -I../os/default -I.. -I../../include/compiler/gcc -I../../include/os/Linux -I../../include         -I/repos/epics/support/sncseq/include -I/repos/epics/epics-base/include/compiler/gcc -I/repos/epics/epics-base/include/os/Linux -I/repos/epics/epics-base/include        -MM -MF osdCpuUtilization.d  ../os/Linux/osdCpuUtilization.c