6.4 Add host statistics, autosave, and regex search
Load Linux host and process metrics (linStat), automatic setpoint persistence
(autosave), and regular-expression database inspection (retools) through
iocsh.bash and the shared commonIocsh startup scripts. Unlike
Run your first IOC, where runtime writes reset when
the Input/Output Controller (IOC) stops, autosave restores your written
process variable (PV) value across restarts over Channel Access (CA) and
pvAccess (PVA).
Prerequisites
- Complete Run your first IOC and Run an IOC with installed modules.
- Confirm that no other IOC on this host publishes the
LOADER_SVC:orLOADER_SVC-as:prefixes.
Open two Bash terminals on the same host with these roles and settings:
| Terminal | Role | Working directory | Environment |
|---|---|---|---|
| Terminal 1 | IOC (iocsh.bash) | ~/ioc-training/loader_services/ | source "$TREE/setEpicsEnv.bash", export EPICS_CA_AUTO_ADDR_LIST=NO EPICS_CA_ADDR_LIST=127.0.0.1, export EPICS_PVA_AUTO_ADDR_LIST=NO EPICS_PVA_ADDR_LIST=127.0.0.1 |
| Terminal 2 | CA and PVA client | Any directory | source "$TREE/setEpicsEnv.bash", export EPICS_CA_AUTO_ADDR_LIST=NO EPICS_CA_ADDR_LIST=127.0.0.1, export EPICS_PVA_AUTO_ADDR_LIST=NO EPICS_PVA_ADDR_LIST=127.0.0.1 |
Create the setpoint database and service startup
-
In both terminals, activate your EPICS-env 1.5.0 tree and direct CA and PVA searches to loopback. If you installed the distribution outside
~/epics, setTREEto that installation’s directory instead of the second line:HOST_ID="$(. /etc/os-release && printf '%s-%s' "$ID" "$VERSION_ID")" TREE="$HOME/epics/1.5.0/$HOST_ID/7.0.10" source "$TREE/setEpicsEnv.bash" export EPICS_CA_AUTO_ADDR_LIST=NO EPICS_CA_ADDR_LIST=127.0.0.1 export EPICS_PVA_AUTO_ADDR_LIST=NO EPICS_PVA_ADDR_LIST=127.0.0.1 -
In terminal 1, create a service directory outside the distribution:
mkdir -p ~/ioc-training/loader_services cd ~/ioc-training/loader_services -
In
~/ioc-training/loader_services/, save this database assetpoint.db:record(ao, "$(P)Setpoint") { field(DESC, "Saved temperature setpoint") field(EGU, "degC") field(VAL, "20") field(PINI, "YES") info(autosaveFields, "VAL") }field(PINI, "YES")processes the analog output (ao) record once duringiocInitso its alarm severity clears toNO_ALARMafter boot-time restore.info(autosaveFields, "VAL")marksVALfor automatic request-file generation byautosave.iocsh. -
Save this startup file as
st.cmdbesidesetpoint.db:on error break module linStat module autosave module retools epicsEnvSet("IOC", "LOADER_SVC") epicsEnvSet("IOCSH_TOP", "$(EPICS_MODULES)/commonIocsh") epicsEnvSet("AS_TOP", "./var") iocshLoad("$(IOCSH_TOP)/iocsh/linStat.iocsh") iocshLoad("$(IOCSH_TOP)/iocsh/autosave.iocsh") dbLoadRecords("setpoint.db", "P=$(IOC):") iocInit()Each setting coordinates
iocsh.bashwithcommonIocsh:module linStat,module autosave, andmodule retoolsload those libraries and exportLINSTAT,AUTOSAVE, andRETOOLSautomatically.IOCis set toLOADER_SVCwithout a trailing colon.autosave.iocshuses$(IOC)as a directory name under./var/LOADER_SVC/and builds the status prefixLOADER_SVC-as:, whilelinStat.iocshsupplies its own colon inLOADER_SVC:UPTIMEandLOADER_SVC:PROCESS_ID. PassingP=$(IOC):todbLoadRecordskeeps$(P)Setpointaligned with the trailing-colonPmacro used across Chapters 3, 4, and 6.- Do not load
linStat.iocshtogether withiocStatsAdmin.iocshin the same IOC. Both fragments define identically named host and process records such as$(IOC):UPTIMEand$(IOC):FD_CNT.
-
Preview the generated startup in terminal 1:
iocsh.bash -n st.cmd
Save a setpoint and inspect live services
-
In terminal 1, start the first IOC run from
~/ioc-training/loader_services/:iocsh.bash st.cmdDuring the initial boot into an empty
./vardirectory,dbrestore.creports that./var/LOADER_SVC/save/settings.savdoes not exist yet. AfteriocInit()completes,afterIocRunninggenerates./var/LOADER_SVC/req/settings.reqfrominfo(autosaveFields, "VAL")and starts a 5-second monitor set. -
At the
iocshprompt in terminal 1, filter loaded record names withreGrep:reGrep("LOADER_SVC:(Setpoint|PROCESS_ID|FD_CNT|UPTIME)")reGrepmatches full record names against a regular expression and prints the four matching records:LOADER_SVC:Setpoint LOADER_SVC:PROCESS_ID LOADER_SVC:FD_CNT LOADER_SVC:UPTIMEUnlike
dbgrep, which uses shell-style*wildcards,reGreprequires the pattern to match the entire record name (.*Setpoint.*or an explicit prefix such asLOADER_SVC:.*). -
In terminal 2, read the initial setpoint,
linStatprocess metrics, andautosavestatus records:caget LOADER_SVC:Setpoint LOADER_SVC:PROCESS_ID LOADER_SVC:FD_CNT LOADER_SVC:UPTIME caget LOADER_SVC-as:SR_0_Name LOADER_SVC-as:SR_statusStrLOADER_SVC:Setpointstarts at20, whilelinStatreports the live IOC process ID (PID), open file-descriptor count, and uptime.PROCESS_IDandFD_CNTread0until their first scan; repeat the read after a few seconds:LOADER_SVC:Setpoint 20 LOADER_SVC:PROCESS_ID 361766 LOADER_SVC:FD_CNT 33 LOADER_SVC:UPTIME 2 S LOADER_SVC-as:SR_0_Name settings LOADER_SVC-as:SR_statusStr Enabling list... -
Write
37.5toLOADER_SVC:Setpointand wait 6 seconds past the default 5-secondSETTINGS_PERIODsave interval:caput LOADER_SVC:Setpoint 37.5 sleep 6CA confirms the setpoint update:
Old : LOADER_SVC:Setpoint 20 New : LOADER_SVC:Setpoint 37.5 -
Inspect the generated request file and saved value file on disk:
cat ~/ioc-training/loader_services/var/LOADER_SVC/req/settings.req cat ~/ioc-training/loader_services/var/LOADER_SVC/save/settings.savsettings.reqlists the tagged field andsettings.savstores37.5before<END>:LOADER_SVC:Setpoint.VAL # autosave R5.3 Automatically generated - DO NOT MODIFY - 261111-102556 LOADER_SVC:Setpoint.VAL 37.5 <END> -
In terminal 1, stop the first IOC run:
exit
Verification
-
In terminal 1, start a second IOC run from
~/ioc-training/loader_services/:iocsh.bash st.cmd -
Without writing to the record, read
LOADER_SVC:Setpointin terminal 2 through CA:caget LOADER_SVC:Setpoint LOADER_SVC:Setpoint.SEVRautosaverestores37.5duringiocInit, andPINIclears the record alarm state toNO_ALARM:LOADER_SVC:Setpoint 37.5 LOADER_SVC:Setpoint.SEVR NO_ALARM -
Read the restored record through PVA:
pvxget LOADER_SVC:Setpointpvxgetconfirmsvalue double = 37.5andalarm.severity int32_t = 0:LOADER_SVC:Setpoint value double = 37.5 alarm.severity int32_t = 0 alarm.status int32_t = 0 alarm.message string = "" timeStamp.secondsPastEpoch int64_t = 1794421561 timeStamp.nanoseconds int32_t = 770665617 timeStamp.userTag int32_t = 0 display.limitLow double = 0 display.limitHigh double = 0 display.description string = "Saved temperature setpoint" display.units string = "degC" display.precision int32_t = 0 display.form.index int32_t = 0 display.form.choices string[] = {7}["Default", "String", "Binary", "Decimal", "Hex", "Exponential", "Engineering"] control.limitLow double = 0 control.limitHigh double = 0 valueAlarm.lowAlarmLimit double = nan valueAlarm.lowWarningLimit double = nan valueAlarm.highWarningLimit double = nan valueAlarm.highAlarmLimit double = nanIn Run your first IOC,
water.dbreturns to0on every restart because no save set writes changes to disk. Enterexitin terminal 1 when finished.