diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 38e5a26..ceb1110 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,17 @@ Release Notes for iocStats -------------------------- +R3.1.16-ALS00.02: August 3,2021 + * Changes by Mirek Dach + - Network statistics was added + - Multiple network ifs could be monitored + - db/ioc_NetStats.db +R3.1.16-ALS00.01: July 1,2021 + * Changes by Mirek Dach + - Not connected Channel access links monitoring was added + - Not connected PVs in Seq programs monitoring was added + - There are two libraries built: + - libdevIocStatsSeq -> for iocs with seqencer + - libdevIocStats -> for iocs without sequencer iocStats-R3-1-15: Nov 3, 2016 * Changes by Mark Rivers: - Improved the layout of the medm files to avoid overlapping widgets, etc. diff --git a/configure/RELEASE b/configure/RELEASE index 6b27de3..ca97235 100644 --- a/configure/RELEASE +++ b/configure/RELEASE @@ -5,18 +5,18 @@ #NOTE: MSI moved to CONFIG_SITE. # SNCSEQ required only if testIocStatsApp will be built. -MAKE_TEST_IOC_APP=YES +#MAKE_TEST_IOC_APP=YES # ============================================================= # Define the version of modules needed by # IOC apps or other Support apps - used by testIocStatsApp # ============================================================= -SUPPORT=/usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support +#SUPPORT=/usr/local/epics/R3.14.11/modules/soft/synApps_5_5/support -SNCSEQ = $(SUPPORT)/seq-2-0-12 - -EPICS_BASE=/afs/slac/g/spear/epics/base +#SNCSEQ = $(SUPPORT)/seq-2-0-12 +EPICS_BASE=/usr/local/epics/R7.0.7/base +#NETWORK_STAT=NO # These lines allow developers to override these RELEASE settings # without having to modify this file directly. -include $(TOP)/../RELEASE.local diff --git a/devIocStats/Makefile b/devIocStats/Makefile index 5acd089..0c0f6bb 100644 --- a/devIocStats/Makefile +++ b/devIocStats/Makefile @@ -14,9 +14,10 @@ INC += devIocStatsOSD.h #============================= -LIBRARY_IOC = devIocStats +LIBRARY_IOC = devIocStats devIocStatsSeq devIocStats_LIBS = $(EPICS_BASE_IOC_LIBS) +devIocStatsSeq_LIBS = $(EPICS_BASE_IOC_LIBS) devIocStats_SYS_LIBS_solaris = kstat devIocStats_SYS_LIBS_WIN32 += psapi @@ -26,7 +27,11 @@ SRCS += devIocStatsString.c SRCS += devIocStatsWaveform.c SRCS += devIocStatsSub.c SRCS += devIocStatsTest.c - +SRCS += ioccar.c +devIocStats_SRCS += seqFunction.c +ifeq ($(NETWORK_STAT),NO) +USR_CFLAGS_Linux += -DNO_NETWORK_STAT +endif # OSD parts # Base 3.14 does not correctly define POSIX=NO for mingw ifeq (mingw,$(findstring mingw, $(T_A))) @@ -35,6 +40,7 @@ endif SRCS += osdCpuUsage.c SRCS += osdCpuUtilization.c SRCS += osdFdUsage.c +SRCS += osdNetStats.c SRCS += osdMemUsage.c SRCS += osdWorkspaceUsage.c SRCS += osdClustInfo.c diff --git a/devIocStats/devIocStats.dbd b/devIocStats/devIocStats.dbd index 39b4d4c..abd11ab 100644 --- a/devIocStats/devIocStats.dbd +++ b/devIocStats/devIocStats.dbd @@ -1,9 +1,11 @@ device(ai,INST_IO,devAiStats,"IOC stats") device(ai,INST_IO,devAiClusts,"IOC stats clusts") +device(ai,INST_IO,devAiNet,"IOC net stats") device(ao,INST_IO,devAoStats,"IOC stats") device(stringin,INST_IO,devStringinStats,"IOC stats") device(stringin,INST_IO,devStringinEnvVar,"IOC env var") device(stringin,INST_IO,devStringinEpics,"IOC epics var") +device(stringin,INST_IO,devStringinNet,"IOC net stats") device(waveform,INST_IO,devWaveformStats,"IOC stats") function(rebootProc) function(scanMonInit) diff --git a/devIocStats/devIocStats.h b/devIocStats/devIocStats.h index 1a76ef8..5da7f62 100644 --- a/devIocStats/devIocStats.h +++ b/devIocStats/devIocStats.h @@ -47,6 +47,7 @@ #define ST_CMD "ST_CMD" #define ENGINEER "ENGINEER" #define LOCATION "LOCATION" +#define WIKI "WIKI" #include "devIocStatsOSD.h" @@ -112,6 +113,16 @@ extern int devIocStatsGetClusterUsage (int pool, int *pval); /* Network Interface Errors */ extern int devIocStatsInitIFErrors (void); extern int devIocStatsGetIFErrors (ifErrInfo *pval); +typedef struct tNetList +{ + char *pcNetIf; + void *pData; + struct tNetList *next; +}tNetList; +#define NET_OK 0 +#define NET_NOK 1 +extern int getPacketStats(void *ifa); +extern int getIpAddr(char *pcIf,char **pcIfAddr); /* Boot Info */ extern int devIocStatsInitBootInfo (void); diff --git a/devIocStats/devIocStatsAnalog.c b/devIocStats/devIocStatsAnalog.c index 7f4ea6e..346cda0 100644 --- a/devIocStats/devIocStatsAnalog.c +++ b/devIocStats/devIocStatsAnalog.c @@ -90,6 +90,9 @@ index - index into cluster array type - 0=size, 1=clusters, 2=free, 3=usage + si (DTYP = "IOC net stats"): + + @netPacketsTx:eth0> ao: memoryScanRate - max rate at which new memory stats can be read @@ -128,6 +131,60 @@ #include #include "devIocStats.h" + +#include +#include +#include +#include +#include +#include +#include +#if !defined(vxWorks) && !defined(__rtems__) && !defined(NO_NETWORK_STAT) +#include +#else +#include "devRtemsNetStats.h" +/* #if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include */ +/*#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +*/ +/* This would otherwise need _KERNEL to be defined... */ +/*extern struct ipstat ipstat; +extern struct udpstat udpstat; +extern struct tcpstat tcpstat; */ /* tcp statistics */ + +#endif +#include + +#define NET_PARAM_SEPARATOR ':' +#define NET_PACKETS_TX "netPacketsTx" +#define NET_PACKETS_RX "netPacketsRx" +#define NET_PACKETS_DROPPED_TX "netPDroppedTx" +#define NET_PACKETS_DROPPED_RX "netPDroppedRx" +#define NET_PACKETS_ERROR_TX "netPErrorTx" +#define NET_PACKETS_ERROR_RX "netPErrorRx" +#define NET_PACKETS_COLLISTIONS "netPCollisions" +#define NET_PACKETS_CARRIER_ERR "netPCarrierErr" + #define BASE_HAS_QUEUE_STATUS (EPICS_VERSION_INT == VERSION_INT(3, 16, 2, 0)) || (EPICS_VERSION_INT >= VERSION_INT(7, 0, 2, 0)) @@ -151,6 +208,17 @@ struct pvtArea }; typedef struct pvtArea pvtArea; + +struct pvtAreaNet +{ + struct pvtArea *pvt; + void *pDataNet; + unsigned short usDataTypeSize; +}; +typedef struct pvtAreaNet pvtAreaNet; + +struct tNetList *ptNetHead=NULL; + struct pvtClustArea { int pool; @@ -188,6 +256,11 @@ static long ai_clusts_init(int pass); static long ai_clusts_init_record(aiRecord *); static long ai_clusts_read(aiRecord *); +/* network related functions */ +static long ai_net_init_record(aiRecord* pr); +static long ai_net_ioint_info(int cmd,aiRecord* pr,IOSCANPVT* iopvt); +static long ai_net_read(aiRecord* pr); + static long ao_init_record(aoRecord* pr); static long ao_write(aoRecord*); @@ -208,6 +281,13 @@ static void statsFdUsage(double*); static void statsFdMax(double*); static void statsCAConnects(double*); static void statsCAClients(double*); +static void statsCALinks(double* val); /*Channel Access DB Links - total number*/ +static void statsCALnconn(double*); /*Channel Access DB Links not connected count*/ +static void statsCALdconn(double*); /*Channel Access DB Links diconncted before count*/ +static void statsSEQProgs(double* val); /*Number of running sequencer programs*/ +static void statsSEQChan(double* val); /*Number of PVs used by sequencer programs*/ +static void statsSEQChanDis(double* val); /*Number of not connected sequencer programs' PVs*/ +static void statsIocHealthy(double* val); /*0 -> not healthy, 1->healthy*/ static void statsMinDataMBuf(double*); static void statsMinSysMBuf(double*); static void statsDataMBuf(double*); @@ -231,6 +311,14 @@ static void statsCbMediumQOverruns(double*); static void statsCbHighQHiWtrMrk(double*); static void statsCbHighQUsed(double*); static void statsCbHighQOverruns(double*); +static void statsNetPacketsProc(double*); +extern long ioccar(char *precordname,int level,int *Pcal, int *Pcalnconn, int *Pcaldconn); +extern epicsShareFunc void seqGatherStats( + unsigned *seq_num_programs, + unsigned *seq_num_channels, + unsigned *seq_num_connected +); + struct { char *name; @@ -240,10 +328,14 @@ struct { { "cpu_scan_rate", 20.0 }, { "fd_scan_rate", 10.0 }, { "ca_scan_rate", 15.0 }, - { "queue_scan_rate", 1.0 }, + { "queue_scan_rate", 1.0 }, { NULL, 0.0 }, }; +#ifdef WITH_NETWORK_SUPPORT + /* add here network support */ +#endif + static validGetParms statsGetParms[]={ { "free_bytes", statsFreeBytes, MEMORY_TYPE }, { "free_blocks", statsFreeBlocks, MEMORY_TYPE }, @@ -263,6 +355,13 @@ static validGetParms statsGetParms[]={ { "maxfd", statsFdMax, FD_TYPE }, { "ca_clients", statsCAClients, CA_TYPE }, { "ca_connections", statsCAConnects, CA_TYPE }, + { "ca_lconn", statsCALinks, CA_TYPE }, + { "ca_lnconn", statsCALnconn, CA_TYPE }, + { "ca_ldconn", statsCALdconn, CA_TYPE }, + { "seq_prog", statsSEQProgs, CA_TYPE }, + { "seq_pvs", statsSEQChan, CA_TYPE }, + { "seq_pvs_dconn", statsSEQChanDis, CA_TYPE }, + { "ioc_health", statsIocHealthy, CA_TYPE }, { "min_data_mbuf", statsMinDataMBuf, MEMORY_TYPE }, { "min_sys_mbuf", statsMinSysMBuf, MEMORY_TYPE }, { "data_mbuf", statsDataMBuf, MEMORY_TYPE }, @@ -286,15 +385,27 @@ static validGetParms statsGetParms[]={ { "cbHighQueueHiWtrMrk", statsCbHighQHiWtrMrk, QUEUE_TYPE }, { "cbHighQueueUsed", statsCbHighQUsed, QUEUE_TYPE }, { "cbHighQueueOverruns", statsCbHighQOverruns, QUEUE_TYPE }, + { NET_PACKETS_TX, statsNetPacketsProc, FD_TYPE }, + { NET_PACKETS_RX, statsNetPacketsProc, FD_TYPE }, + { NET_PACKETS_DROPPED_TX, statsNetPacketsProc, FD_TYPE }, + { NET_PACKETS_DROPPED_RX, statsNetPacketsProc, FD_TYPE }, + { NET_PACKETS_ERROR_TX, statsNetPacketsProc, FD_TYPE }, + { NET_PACKETS_ERROR_RX, statsNetPacketsProc, FD_TYPE }, + { NET_PACKETS_COLLISTIONS, statsNetPacketsProc, FD_TYPE }, + { NET_PACKETS_CARRIER_ERR, statsNetPacketsProc, FD_TYPE }, { NULL,NULL,0 } }; + aStats devAiStats={ 6,NULL,ai_init,ai_init_record,ai_ioint_info,ai_read,NULL }; epicsExportAddress(dset,devAiStats); aStats devAoStats={ 6,NULL,NULL,ao_init_record,NULL,ao_write,NULL }; epicsExportAddress(dset,devAoStats); aStats devAiClusts = {6,NULL,ai_clusts_init,ai_clusts_init_record,NULL,ai_clusts_read,NULL }; epicsExportAddress(dset,devAiClusts); +aStats devAiNet={ 6,NULL,NULL,ai_net_init_record,ai_net_ioint_info,ai_net_read,NULL }; +epicsExportAddress(dset,devAiNet); + static memInfo meminfo = {0.0,0.0,0.0,0.0,0.0,0.0}; static memInfo workspaceinfo = {0.0,0.0,0.0,0.0,0.0,0.0}; @@ -313,6 +424,13 @@ static int mbufnumber[2] = {0,0}; static ifErrInfo iferrors = {0,0}; static unsigned cainfo_clients = 0; static unsigned cainfo_connex = 0; +static unsigned cainfo_lnconn = 0; +static unsigned cainfo_ldconn = 0; +static unsigned cainfo_links =0; +static unsigned seq_num_programs =0; +static unsigned seq_num_channels =0; +static unsigned seq_num_DisConnected=0; + static epicsTimerQueueId timerQ = 0; static epicsMutexId scan_mutex; static int caServInitialized = 0; @@ -398,6 +516,7 @@ static void scan_time(int type) { fdInfo fdusage_local = {0,0}; devIocStatsGetFDUsage(&fdusage_local); + getPacketStats((void *) ptNetHead); /* get network statistics */ epicsMutexLock(scan_mutex); fdusage = fdusage_local; epicsMutexUnlock(scan_mutex); @@ -407,6 +526,12 @@ static void scan_time(int type) { unsigned cainfo_clients_local = 0; unsigned cainfo_connex_local = 0; + int cainfo_lnconn_local = 0; + int cainfo_ldconn_local = 0; + int cainfo_links_local =0; + unsigned seq_num_programs_local =0; + unsigned seq_num_channels_local =0; + unsigned seq_num_connected_local=0; /* Guard to ensure that the caServ is initialized */ if (!caServInitialized) { @@ -414,9 +539,20 @@ static void scan_time(int type) } casStatsFetch(&cainfo_connex_local, &cainfo_clients_local); + ioccar(0, 0, &cainfo_links_local, &cainfo_lnconn_local, &cainfo_ldconn_local); + seqGatherStats(&seq_num_programs_local,&seq_num_channels_local,&seq_num_connected_local); + + epicsMutexLock(scan_mutex); cainfo_clients = cainfo_clients_local; cainfo_connex = cainfo_connex_local; + cainfo_links = cainfo_links_local; + cainfo_lnconn = cainfo_lnconn_local; + cainfo_ldconn = cainfo_ldconn_local; + /* sequencer related variables */ + seq_num_programs = seq_num_programs_local; + seq_num_channels = seq_num_channels_local; + seq_num_DisConnected = seq_num_channels_local - seq_num_connected_local; epicsMutexUnlock(scan_mutex); break; } @@ -683,6 +819,183 @@ static long ai_read(aiRecord* pr) pr->udf = 0; return 2; /* don't convert */ } + + +/* network related functions */ +static short addListNode(tNetList **ptNetList,char *if_name); +static long ai_net_init_record(aiRecord* pr) +{ + int i; + pvtArea *pvt = NULL; + struct tNetList *ptNetList=NULL; + char *parm; + char *pcIfName=NULL; + unsigned short sParamLen=0; + unsigned short sIfNameLen=0; + pvtAreaNet *pvtNet = NULL; + + + if(pr->inp.type!=INST_IO) + { + recGblRecordError(S_db_badField,(void*)pr, + "devAiStats (init_record) Illegal INP field"); + return S_db_badField; + } + parm = pr->inp.value.instio.string; + pcIfName=strchr(parm,NET_PARAM_SEPARATOR); + if(pcIfName){ + sParamLen=pcIfName-parm; + pcIfName=pcIfName+1; + sIfNameLen=strlen(pcIfName); + } + + if(pcIfName==NULL || sIfNameLen<2 || strchr(pcIfName,' ')!=NULL){ + recGblRecordError(S_db_badField,(void*)pr, + "devAiStats (init_record) Illegal INP field"); + fprintf( stderr, "example: INP = @%s%ceth0\n",parm,NET_PARAM_SEPARATOR); + return S_db_badField; + } + for(i=0;statsGetParms[i].name && pvt==NULL && pvtNet==NULL;i++) + { + if(strncmp(parm,statsGetParms[i].name,sParamLen)==0) + { + pvt=(pvtArea*)malloc(sizeof(pvtArea)); + pvt->index=i; + pvt->type=statsGetParms[i].type; + + /* Network specyfic data */ + pvtNet=(pvtAreaNet*)malloc(sizeof(pvtAreaNet)); + pvtNet->pvt=pvt; + /* if(addListNode(&ptNetList,pr->sval) != NET_OK) */ + if(addListNode(&ptNetList,pcIfName)==NET_OK){ /* add an entry to the list with the interface name */ + if(ptNetList->pcNetIf==NULL){ /* if network interface in pr->sval is not yet defined then create it */ + ptNetList->pcNetIf=malloc(sizeof(char) * (sIfNameLen+1)); + if(ptNetList->pcNetIf==NULL){ + recGblRecordError(S_db_noMemory,(void*)pr, + "devAiStats (init_record) momory alocation for ptNetList->pcNetIf failed"); + return S_db_noMemory; + } + sprintf(ptNetList->pcNetIf,"%s",pcIfName); + } + if(ptNetList->pData==NULL){ + ptNetList->pData=malloc(sizeof(struct rtnl_link_stats)); + if(ptNetList->pData==NULL){ + recGblRecordError(S_db_noMemory,(void*)pr, + "devAiStats (init_record) momory alocation for ptNetList->pData failed"); + return S_db_noMemory; + } + } + if(strncmp(parm,NET_PACKETS_TX,sParamLen)==0){ + pvtNet->pDataNet=(void *)&(((struct rtnl_link_stats *)ptNetList->pData)->tx_packets); + pvtNet->usDataTypeSize=sizeof(((struct rtnl_link_stats *)0)->tx_packets); + } + else if(strncmp(parm,NET_PACKETS_RX,sParamLen)==0){ + pvtNet->pDataNet=(void *)&(((struct rtnl_link_stats *)ptNetList->pData)->rx_packets); + pvtNet->usDataTypeSize=sizeof(((struct rtnl_link_stats *)0)->rx_packets); + } + else if(strncmp(parm,NET_PACKETS_DROPPED_TX,sParamLen)==0){ + pvtNet->pDataNet=(void *)&(((struct rtnl_link_stats *)ptNetList->pData)->tx_dropped); + pvtNet->usDataTypeSize=sizeof(((struct rtnl_link_stats *)0)->tx_dropped); + } + else if(strncmp(parm,NET_PACKETS_DROPPED_RX,sParamLen)==0){ + pvtNet->pDataNet=(void *)&(((struct rtnl_link_stats *)ptNetList->pData)->rx_dropped); + pvtNet->usDataTypeSize=sizeof(((struct rtnl_link_stats *)0)->rx_dropped); + } + else if(strncmp(parm,NET_PACKETS_ERROR_TX,sParamLen)==0){ + pvtNet->pDataNet=(void *)&(((struct rtnl_link_stats *)ptNetList->pData)->tx_errors); + pvtNet->usDataTypeSize=sizeof(((struct rtnl_link_stats *)0)->tx_errors); + } + else if(strncmp(parm,NET_PACKETS_ERROR_RX,sParamLen)==0){ + pvtNet->pDataNet=(void *)&(((struct rtnl_link_stats *)ptNetList->pData)->rx_errors); + pvtNet->usDataTypeSize=sizeof(((struct rtnl_link_stats *)0)->rx_errors); + } + else if(strncmp(parm,NET_PACKETS_COLLISTIONS,sParamLen)==0){ + pvtNet->pDataNet=(void *)&(((struct rtnl_link_stats *)ptNetList->pData)->collisions); + pvtNet->usDataTypeSize=sizeof(((struct rtnl_link_stats *)0)->collisions); + } + else if(strncmp(parm,NET_PACKETS_CARRIER_ERR,sParamLen)==0){ + pvtNet->pDataNet=(void *)&(((struct rtnl_link_stats *)ptNetList->pData)->tx_carrier_errors); + pvtNet->usDataTypeSize=sizeof(((struct rtnl_link_stats *)0)->tx_carrier_errors); + } + + + /* just for debug purpose */ + /* tNetList *ptNetListDebug; + ptNetListDebug=ptNetHead; + while(ptNetListDebug){ + printf("DEBUG: if net name %s\n",ptNetListDebug->pcNetIf); + ptNetListDebug=ptNetListDebug->next; + } + printf("----------------------------\n\n"); + */ + }/* if(addListNode(&ptNetList,pr->sval)==NET_OK */ + } + }/* end of for */ + + if(pvt==NULL) + { + recGblRecordError(S_db_badField,(void*)pr, + "devAiStats (init_record) Illegal INP parm field"); + return S_db_badField; + } + /* Make sure record processing routine does not perform any conversion*/ + pr->linr=menuConvertNO_CONVERSION; + pr->dpvt=pvtNet; + return 0; +} + +static long ai_net_ioint_info(int cmd,aiRecord* pr,IOSCANPVT* iopvt) +{ + pvtAreaNet* pvtNet=(pvtAreaNet*)pr->dpvt; + pvtArea* pvt=NULL; + + if (!pvtNet) return S_dev_badInpType; + pvt=pvtNet->pvt; + if (!pvt) return S_dev_badInpType; + if(cmd==0) /* added */ + { + if(scan[pvt->type].total++ == 0) + { + /* start a watchdog */ + epicsTimerStartDelay(scan[pvt->type].wd, scan[pvt->type].rate_sec); + scan[pvt->type].on=1; + } + } + else /* deleted */ + { + if(--scan[pvt->type].total == 0) + scan[pvt->type].on=0; /* stop the watchdog */ + } + *iopvt=scan[pvt->type].ioscan; + return 0; +} + +static long ai_net_read(aiRecord* pr) +{ + //double val; + double dVal=0; + pvtAreaNet* pvtNet=(pvtAreaNet*)pr->dpvt; + //pvtArea* pvt=(pvtArea*)pr->dpvt; + + if (!pvtNet) return S_dev_badInpType; + + epicsMutexLock(scan_mutex); + //statsGetParms[pvt->index].func(&val); + if(pvtNet->usDataTypeSize == sizeof(__u32)) + dVal=*(__u32 *)(pvtNet->pDataNet); + else if(pvtNet->usDataTypeSize == sizeof(__u64)) + dVal=*(__u64 *)(pvtNet->pDataNet); + else if(pvtNet->usDataTypeSize == sizeof(__u8)) + dVal=*(__u8 *)(pvtNet->pDataNet); + else if(pvtNet->usDataTypeSize == sizeof(__u16)) + dVal=*(__u16 *)(pvtNet->pDataNet); + epicsMutexUnlock(scan_mutex); + pr->val=dVal; + //pr->val = val; + pr->udf = 0; + return 2; /* don't convert */ +} + /* -------------------------------------------------------------------- */ @@ -692,7 +1005,7 @@ static double minMBuf(int pool) int i = 0; double lowest = 1.0, comp; - while ((i < CLUSTSIZES) && (clustinfo[pool][i][0] != 0)) + while ((clustinfo[pool][i][0] != 0) && (i < CLUSTSIZES)) { if (clustinfo[pool][i][1] != 0) { comp = ((double)clustinfo[pool][i][2]) / clustinfo[pool][i][1]; @@ -940,3 +1253,98 @@ static void statsCbHighQOverruns(double *val) *val = 0; #endif } + + +static void statsCALinks(double* val) +{ + *val=(double)cainfo_links; +} + +static void statsCALnconn(double* val) +{ + *val=(double)cainfo_lnconn; +} + +static void statsCALdconn(double* val) +{ + *val=(double)cainfo_ldconn; +} + +static void statsSEQProgs(double* val) +{ + *val=(double)seq_num_programs; +} + +static void statsSEQChan(double* val) +{ + *val=(double)seq_num_channels; +} + +static void statsSEQChanDis(double* val) +{ + *val=(double)seq_num_DisConnected; +} + +static void statsIocHealthy(double* val) +{ + if(seq_num_DisConnected || cainfo_ldconn || cainfo_lnconn) + *val=0; /* Ioc not healthy */ + else + *val=1; /* Ioc healthy */ +} + +static void statsNetPacketsProc(double* val){ + +} + +static short addListNode(tNetList **ptNetList,char *if_name){ + struct tNetList *ptNetListLast=NULL; + + if(if_name==NULL) + return NET_NOK; + if(strlen(if_name)==0) + return NET_NOK; + + if(ptNetHead==NULL){ + /* create head of the linked list */ + ptNetHead=malloc(sizeof(tNetList)); + if(ptNetHead==NULL){ + fprintf( stderr, "addListNode: momory alocation for ptNetHead failed\n"); + return NET_NOK; + } + ptNetHead->pcNetIf=NULL; + ptNetHead->pData=NULL; + ptNetHead->next=NULL; + *ptNetList=ptNetHead; + } + else{ + /* list has already a head */ + *ptNetList=ptNetHead; + ptNetListLast=NULL; + while(*ptNetList){ + if((*ptNetList)->pcNetIf==NULL){ + break; /* ptNetList element alredy exists but interface name pcNetIf was not set so use this element */ + } + if(!strcmp((*ptNetList)->pcNetIf,if_name)){ + return NET_OK; /* the entry already exists */ + } + ptNetListLast=*ptNetList; + *ptNetList=(*ptNetList)->next; + } + if(*ptNetList==NULL){ + *ptNetList=ptNetListLast; + (*ptNetList)->next=malloc(sizeof(tNetList)); + if((*ptNetList)->next==NULL){ + fprintf( stderr, "addListNode: momory alocation for ptNetList failed\n"); + return NET_NOK; + } + *ptNetList=(*ptNetList)->next; + (*ptNetList)->pcNetIf=NULL; + (*ptNetList)->pData=NULL; + (*ptNetList)->next=NULL; + + }/* if(ptNetList==NULL){ */ + } + return NET_OK; +} + diff --git a/devIocStats/devIocStatsString.c b/devIocStats/devIocStatsString.c index fe83205..623fefa 100644 --- a/devIocStats/devIocStatsString.c +++ b/devIocStats/devIocStatsString.c @@ -80,6 +80,10 @@ stringin (DTYP = "IOC epics var"): + + stringin (DTYP = "IOC net stats"): + + */ #include @@ -98,6 +102,9 @@ #include #include "devIocStats.h" +#include + +#define NET_PARAM_SEPARATOR ':' #define MAX_NAME_SIZE (MAX_STRING_SIZE-1) @@ -136,6 +143,8 @@ static long envvar_init_record(stringinRecord*); static long envvar_read(stringinRecord*); static long epics_init_record(stringinRecord*); static long epics_read(stringinRecord*); +static long stringin_net_init_record(stringinRecord* pr); +static long net_read(stringinRecord*); static void statsSScript1(char *); static void statsSScript2(char *); @@ -150,13 +159,16 @@ static void statsKernelVer(char *); static void statsEPICSVer(char *); static void statsEngineer(char *); static void statsLocation(char *); +static void statsWiki(char *); static void statsUpTime(char *); static void statsHostName(char *); static void statsPwd1(char *); static void statsPwd2(char *); +static void statsNetAddr(char *); static int devIocStatsGetEngineer (char **pval); static int devIocStatsGetLocation (char **pval); +static int devIocStatsGetWiki (char **pval); static validGetStrParms statsGetStrParms[]={ { "startup_script_1", statsSScript1, STATIC_TYPE }, @@ -172,19 +184,23 @@ static validGetStrParms statsGetStrParms[]={ { "epics_ver", statsEPICSVer, STATIC_TYPE }, { "engineer", statsEngineer, STATIC_TYPE }, { "location", statsLocation, STATIC_TYPE }, + { "wiki", statsWiki, STATIC_TYPE }, { "up_time", statsUpTime, STATIC_TYPE }, { "hostname", statsHostName, STATIC_TYPE }, { "pwd1", statsPwd1, STATIC_TYPE }, { "pwd2", statsPwd2, STATIC_TYPE }, + { "netAddr", statsNetAddr, STATIC_TYPE }, { NULL,NULL,0 } }; sStats devStringinStats ={5,NULL,stringin_init,stringin_init_record,NULL,stringin_read}; sStats devStringinEnvVar ={5,NULL,NULL,envvar_init_record, NULL,envvar_read }; sStats devStringinEpics ={5,NULL,NULL,epics_init_record, NULL,epics_read }; +sStats devStringinNet ={5,NULL,NULL,stringin_net_init_record, NULL,net_read }; epicsExportAddress(dset,devStringinStats); epicsExportAddress(dset,devStringinEnvVar); epicsExportAddress(dset,devStringinEpics); +epicsExportAddress(dset,devStringinNet); static char *notavail = ""; static char *empty = ""; @@ -282,7 +298,6 @@ static long epics_init_record(stringinRecord* pr) static long stringin_read(stringinRecord* pr) { pvtArea* pvt=(pvtArea*)pr->dpvt; - if (!pvt) return S_dev_badInpType; statsGetStrParms[pvt->index].func(pr->val); @@ -314,7 +329,65 @@ static long epics_read(stringinRecord* pr) } return(0); /* success */ } - + +static long stringin_net_init_record(stringinRecord* pr) +{ + int i; + char *parm; + char *pcIfName=NULL; + unsigned short sParamLen=0; + unsigned short sIfNameLen=0; + pvtArea *pvt = NULL; + if(pr->inp.type!=INST_IO) + { + recGblRecordError(S_db_badField,(void*)pr, + "devStringinStats (init_record) Illegal INP field"); + return S_db_badField; + } + parm = pr->inp.value.instio.string; + pcIfName=strchr(parm,NET_PARAM_SEPARATOR); + if(pcIfName){ + sParamLen=pcIfName-parm; + pcIfName=pcIfName+1; + sIfNameLen=strlen(pcIfName); + } + + if(pcIfName==NULL || sIfNameLen<2 || strchr(pcIfName,' ')!=NULL){ + recGblRecordError(S_db_badField,(void*)pr, + "devAiStats (init_record) Illegal INP field"); + fprintf( stderr, "example: INP = @%s%ceth0\n",parm,NET_PARAM_SEPARATOR); + return S_db_badField; + } + + for(i=0;statsGetStrParms[i].name && pvt==NULL;i++) + { + if(strncmp(parm,statsGetStrParms[i].name,sParamLen)==0) + { + pvt=(pvtArea*)malloc(sizeof(pvtArea)); + pvt->index=i; + pvt->type=statsGetStrParms[i].type; + } + } + if(pvt==NULL) + { + recGblRecordError(S_db_badField,(void*)pr, + "devStringinStats (init_record) Illegal INP parm field"); + return S_db_badField; + } + + pr->dpvt=pvt; + return 0; /* success */ +} + +static long net_read(stringinRecord* pr) +{ + pvtArea* pvt=(pvtArea*)pr->dpvt; + if (!pvt) return S_dev_badInpType; + statsGetStrParms[pvt->index].func((char *)pr); + pr->udf=0; + return(0); /* success */ +} + /* -------------------------------------------------------------------- */ typedef int getStringFunc (char **dest); @@ -345,6 +418,7 @@ static void statsBootline6(char *d) { getStringPart(d, 5*MAX_NAME_SIZE, devIocSt static void statsEngineer(char *d) { getStringPart(d, 0, devIocStatsGetEngineer); } static void statsLocation(char *d) { getStringPart(d, 0, devIocStatsGetLocation); } +static void statsWiki(char *d) { getStringPart(d, 0, devIocStatsGetWiki); } static void statsBSPRev(char *d) { getStringPart(d, 0, devIocStatsGetBSPVersion); } static void statsKernelVer(char *d) { getStringPart(d, 0, devIocStatsGetKernelVersion); } @@ -410,6 +484,19 @@ static int devIocStatsGetLocation (char **pval) if (sp == notavail) return -1; return 0; } +static int devIocStatsGetWiki (char **pval) +{ + char *spbuf; + char **sppbuf; + char *sp = notavail; + + /* Get value from environment or global variable */ + if ((spbuf = getenv(WIKI))) sp = spbuf; + else if ((sppbuf = epicsFindSymbol("wiki"))) sp = *sppbuf; + *pval = sp; + if (sp == notavail) return -1; + return 0; +} int devIocStatsGetStartupScriptDefault (char **pval) { char *spbuf; @@ -442,3 +529,35 @@ int devIocStatsGetStartupScriptDefault (char **pval) if (sp == notavail) return -1; return 0; } + +static void statsNetAddr(char *p){ + stringinRecord* pr=NULL; + char *pcIfAddr=NULL; + char *parm; + char *pcIfName=NULL; + //unsigned short sParamLen=0; + unsigned short sIfNameLen=0; + + + pr=(stringinRecord *)p; + + parm = pr->inp.value.instio.string; + pcIfName=strchr(parm,NET_PARAM_SEPARATOR); + if(pcIfName){ + //sParamLen=pcIfName-parm; + pcIfName=pcIfName+1; + sIfNameLen=strlen(pcIfName); + } + + if(pcIfName==NULL || sIfNameLen<2 || strchr(pcIfName,' ')!=NULL){ + fprintf( stderr,"devAiStats (read_record) Illegal INP field\n"); + fprintf( stderr, "example: INP = @%s%ceth0\n",parm,NET_PARAM_SEPARATOR); + return; + } + /* find the IP address for given interface in INP filed after : files */ + if( getIpAddr(pcIfName,&pcIfAddr) == NET_OK){ + if(pcIfAddr) + snprintf(pr->val,40,"%s",pcIfAddr); /* string in VAL size = 40 and is hard coded */ + } + +} diff --git a/devIocStats/devRtemsNetStats.h b/devIocStats/devRtemsNetStats.h new file mode 100644 index 0000000..ec95d69 --- /dev/null +++ b/devIocStats/devRtemsNetStats.h @@ -0,0 +1,39 @@ +#define __u64 unsigned long long int +#define __u32 unsigned long int +#define __u16 unsigned short +#define __u8 unsigned char + +struct rtnl_link_stats { + __u32 rx_packets; /* total packets received */ + __u32 tx_packets; /* total packets transmitted */ + __u32 rx_bytes; /* total bytes received */ + __u32 tx_bytes; /* total bytes transmitted */ + __u32 rx_errors; /* bad packets received */ + __u32 tx_errors; /* packet transmit problems */ + __u32 rx_dropped; /* no space in linux buffers */ + __u32 tx_dropped; /* no space available in linux */ + __u32 multicast; /* multicast packets received */ + __u32 collisions; + + /* detailed rx_errors: */ + __u32 rx_length_errors; + __u32 rx_over_errors; /* receiver ring buff overflow */ + __u32 rx_crc_errors; /* recved pkt with crc error */ + __u32 rx_frame_errors; /* recv'd frame alignment error */ + __u32 rx_fifo_errors; /* recv'r fifo overrun */ + __u32 rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + __u32 tx_aborted_errors; + __u32 tx_carrier_errors; + __u32 tx_fifo_errors; + __u32 tx_heartbeat_errors; + __u32 tx_window_errors; + + /* for cslip etc */ + __u32 rx_compressed; + __u32 tx_compressed; + + __u32 rx_nohandler; /* dropped, no handler found */ +}; + diff --git a/devIocStats/ioccar.c b/devIocStats/ioccar.c new file mode 100755 index 0000000..927fd23 --- /dev/null +++ b/devIocStats/ioccar.c @@ -0,0 +1,152 @@ +/* ioccar.c */ +/***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +(C) COPYRIGHT 1991 Regents of the University of California, +and the University of Chicago Board of Governors. + +This software was developed under a United States Government license +described on the COPYRIGHT_Combined file included as part +of this distribution. +**********************************************************************/ + +/**************************************************************** +* +* Current Author: Marty Kraimer +* Date: 10APR96 +* +* +* Modification Log: +* ----------------- +* .01 10APR96 mrk list db to CA links +****************************************************************/ + +#if defined(NO_NETWORK_STAT) + +long ioccar(char *precordname,int level, int *Pcal, int *Pcalnconn, int *Pcaldconn) { return 0; }; + +#else + +#if defined(vxWorks) +#include +#endif +#include +#include +#include +#include +#if defined(vxWorks) +#include +#endif +#include "dbStaticLib.h" +#include "link.h" +/*definitions needed because of old vs new database access*/ +#undef DBR_SHORT +#undef DBR_PUT_ACKT +#undef DBR_PUT_ACKS +#undef VALID_DB_REQ +#undef INVALID_DB_REQ +/*end of conflicting definitions*/ +#include "cadef.h" +#include "dbDefs.h" +#include "epicsPrint.h" +#include "dbCommon.h" +#include "dbCa.h" +#include +#define LT_EPICSBASE(v,r,l) ((EPICS_VERSION<=(v)) && (EPICS_REVISION<=(r)) && (EPICS_MODIFICATION<(l))) +#define GT_EPICSBASE(v,r,l) ((EPICS_VERSION>=(v)) && (EPICS_REVISION>=(r)) && (EPICS_MODIFICATION>(l))) +#if LT_EPICSBASE(3,14,13) +#include "../src/db/dbCaPvt.h" +#elif GT_EPICSBASE(7,0,0) +#include "../modules/database/src/ioc/db/dbCaPvt.h" +#else +#include "../src/ioc/db/dbCaPvt.h" +#endif +extern struct dbBase *pdbbase; + +long ioccar(char *precordname,int level, int *Pcal, int *Pcalnconn, int *Pcaldconn) +{ + DBENTRY dbentry; + DBENTRY *pdbentry=&dbentry; + long status; + dbCommon *precord; + dbRecordType *pdbRecordType; + dbFldDes *pdbFldDes; + DBLINK *plink; + int ncalinks=0; + int nconnected=0; + int noReadAccess=0; + int noWriteAccess=0; + unsigned long nDisconnect=0; + unsigned long nNoWrite=0; + caLink *pca; + int j; + + + dbInitEntry(pdbbase,pdbentry); + status = dbFirstRecordType(pdbentry); + while(!status) { + status = dbFirstRecord(pdbentry); + while(!status) { + if(!precordname + || (strcmp(precordname,dbGetRecordName(pdbentry)) ==0)) { + pdbRecordType = pdbentry->precordType; + precord = (dbCommon *)pdbentry->precnode->precord; + for(j=0; jno_links; j++) { + pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->link_ind[j]]; + plink = (DBLINK *)((char *)precord + pdbFldDes->offset); + if (plink->type == CA_LINK) { + ncalinks++; + pca = (caLink *)plink->value.pv_link.pvt; + if(pca && (ca_field_type(pca->chid) != TYPENOTCONN)) { + nconnected++; + nDisconnect += pca->nDisconnect; + nNoWrite += pca->nNoWrite; + if(!ca_read_access(pca->chid)) noReadAccess++; + if(!ca_write_access(pca->chid)) noWriteAccess++; + if(level>1) { + printf(" connected "); + printf("%s",ca_host_name(pca->chid)); + if(!ca_read_access(pca->chid)) + printf(" no_read_access"); + if(!ca_write_access(pca->chid)) + printf(" no_write_access"); + printf(" %s.%s %s", + precord->name, + pdbFldDes->name, + plink->value.pv_link.pvname); + if(nDisconnect) + printf(" nDisconnect %lu",pca->nDisconnect); + if(nNoWrite) + printf(" nNoWrite %lu",pca->nNoWrite); + printf("\n"); + } + } else { + if(level>0) { + printf("not_connected %s.%s %s", + precord->name, + pdbFldDes->name, + plink->value.pv_link.pvname); + if(nDisconnect) + printf(" nDisconnect %lu",pca->nDisconnect); + if(nNoWrite) + printf(" nNoWrite %lu",pca->nNoWrite); + printf("\n"); + } + } + } + } + if(precordname) goto done; + } + status = dbNextRecord(pdbentry); + } + status = dbNextRecordType(pdbentry); + } +done: + *Pcal = ncalinks; + *Pcalnconn = (ncalinks - nconnected); + *Pcaldconn = nDisconnect; + dbFinishEntry(pdbentry); + return(0); +} +#endif diff --git a/devIocStats/os/Linux/osdNetStats.c b/devIocStats/os/Linux/osdNetStats.c new file mode 100644 index 0000000..e8b837a --- /dev/null +++ b/devIocStats/os/Linux/osdNetStats.c @@ -0,0 +1,132 @@ +#if defined(NO_NETWORK_STAT) + +#include "devIocStats.h" + +int getPacketStats( void * ptNetHeadVoid){ + return NET_NOK; +} + +int getIpAddr(char *pcIf,char **pcIfAddr){ + return NET_NOK; +} + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int getPacketStats( void * ptNetHeadVoid){ + struct ifaddrs *ifaddr; + int family; + struct ifaddrs *ifa=NULL; + short sRet=NET_OK; + struct tNetList *ptNetList=NULL; + struct tNetList *ptNetHead; + + ptNetHead=(struct tNetList *)ptNetHeadVoid; + + if(ptNetHead==NULL) + return NET_NOK; + + + if (getifaddrs(&ifaddr) == -1) { + perror("getifaddrs"); + return NET_NOK; + } + + /* Walk through linked list, maintaining head pointer so we can free list later. */ + + for (ifa = ifaddr; ifa != NULL; + ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + family = ifa->ifa_addr->sa_family; + if (family == AF_PACKET && ifa->ifa_data != NULL) { + /*struct rtnl_link_stats *stats = ifa->ifa_data; + + printf("\t\ttx_packets = %10u; rx_packets = %10u\n" + "\t\ttx_bytes = %10u; rx_bytes = %10u\n" + "\t\ttx_dropped = %10u; rx_dropped = %10u\n" + "\t\tmulticast = %10u; collisions = %10u\n", + stats->tx_packets, stats->rx_packets, + stats->tx_bytes, stats->rx_bytes, + stats->tx_dropped, stats->rx_dropped, + stats->multicast, stats->collisions); + printf("sizeof %lu\n",sizeof(stats->tx_packets)); + */ + ptNetList=ptNetHead; + while(ptNetList){ + if(ptNetList->pcNetIf!=NULL){ + if(!(strcmp(ptNetList->pcNetIf,ifa->ifa_name))){ + if(ptNetList->pData!=NULL){ + memcpy((void *)(ptNetList->pData),(void *)(ifa->ifa_data),sizeof(struct rtnl_link_stats)); + } + } + } + ptNetList=ptNetList->next; + } + }/* if (family == AF_PACKET && ifa->ifa_data != NULL) { */ + + }/* for (ifa = ifaddr; ifa != NULL; */ + + freeifaddrs(ifaddr); + return sRet; +} + +int getIpAddr(char *pcIf,char **pcIfAddr){ + struct ifaddrs *ifaddr; + int family, s; + char host[NI_MAXHOST]; + struct ifaddrs *ifa=NULL; + short sRet=NET_OK; + + if (getifaddrs(&ifaddr) == -1) { + perror("getifaddrs"); + return NET_NOK; + } + + /* Walk through linked list, maintaining head pointer so we can free list later. */ + + for (ifa = ifaddr; ifa != NULL; + ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + family = ifa->ifa_addr->sa_family; + if (family == AF_INET) { + if (strcmp(pcIf,ifa->ifa_name)){ + continue; + } + s = getnameinfo(ifa->ifa_addr, + sizeof(struct sockaddr_in) , + host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST); + if (s != 0) { + fprintf(stderr, "getIpAddr:getnameinfo() failed: %s\n", gai_strerror(s)); + sRet=NET_NOK; + break; + } + if(*pcIfAddr==NULL){ + *pcIfAddr=malloc(sizeof(char)*(strlen(host)+1)); + if(*pcIfAddr==NULL){ + fprintf(stderr, "getIpAddr: pcIfAddr=malloc failed\n"); + sRet=NET_NOK; + break; + } + sprintf(*pcIfAddr,"%s",host); /* cpoty IP address */ + sRet=NET_OK; + break; + } + }/* if (family == AF_INET) { */ + }/* for (ifa = ifaddr; ifa != NULL; */ + freeifaddrs(ifaddr); + return sRet; +} +#endif + diff --git a/devIocStats/os/RTEMS/devIocStatsOSD.h b/devIocStats/os/RTEMS/devIocStatsOSD.h index b21cc0e..2b252da 100644 --- a/devIocStats/os/RTEMS/devIocStatsOSD.h +++ b/devIocStats/os/RTEMS/devIocStatsOSD.h @@ -66,6 +66,10 @@ # endif #include +#if (__RTEMS_MAJOR__ == 5) +#undef random +#endif + #include #define sysBootLine rtems_bsdnet_bootp_cmdline @@ -79,6 +83,7 @@ #elif (defined(__PPC__) && ((__RTEMS_MAJOR__ > 4) \ || (__RTEMS_MAJOR__ == 4 && __RTEMS_MINOR__ > 9) \ || (__RTEMS_MAJOR__ == 4 && __RTEMS_MINOR__ == 9 && __RTEMS_REVISION__ > 0))) +#include #define reboot(x) bsp_reset() #else #define reboot(x) rtemsReboot() diff --git a/devIocStats/os/RTEMS/osdCpuUsage.c b/devIocStats/os/RTEMS/osdCpuUsage.c index 2daa95e..781ee5b 100644 --- a/devIocStats/os/RTEMS/osdCpuUsage.c +++ b/devIocStats/os/RTEMS/osdCpuUsage.c @@ -46,7 +46,118 @@ */ #include +# if (__RTEMS_MAJOR__ >= 5) +#include +//This include below contains the report +#include +#include +#include +#include +#include +#include +#include +// CPU usage document +// https://docs.rtems.org/branches/master/c-user/cpu_usage_statistics.html + +//Taken from +//./kernel/cpukit/libmisc/cpuuse/cpuuseimpl.h + +//implemention based on the function rtems_cpu_usage_report_with_plugin and cpu_usage_visitor in +////./kernel/cpukit/libmisc/cpuuse/cpuusagereport.c +typedef struct { + double dTotal; /* seconds */ + double dIdle; /* seconds */ + uint32_t uiThreads_cnt; /* number of threads */ +} epics_cpu_usage_context; + +static uint32_t iocstats_tick_interval=0; + +static bool epics_cpu_usage_visitor( Thread_Control *the_thread, void *arg ) +{ + epics_cpu_usage_context *ctx; + char name[ 38 ]; + Timestamp_Control used; + + if(!iocstats_tick_interval){ + iocstats_tick_interval = (uint32_t) (SBT_1US * rtems_configuration_get_microseconds_per_tick()); + iocstats_tick_interval = iocstats_tick_interval/1000; /* milisecond */ + } + + ctx = arg; + _Thread_Get_name( the_thread, name, sizeof( name ) ); + + _Thread_Get_CPU_time_used( the_thread, &used ); + + ctx->uiThreads_cnt++; // count number of threads + ctx->dTotal += ((double)(used/iocstats_tick_interval))/100000; /* seconds */ + + if(name[0]=='I' && name[1]=='D' && name[2]=='L' && name[3]=='E'){ + ctx->dIdle = ((double)(used/iocstats_tick_interval))/100000; /* seconds */ + } + + return false; +} + + +static double prev_total = 0; +static double prev_idle = 0; + + +int devIocStatsInitCpuUsage (void) +{ + epics_cpu_usage_context ctx; + + ctx.dTotal=0; + ctx.dIdle=0; + ctx.uiThreads_cnt=0; + + rtems_task_iterate( epics_cpu_usage_visitor, &ctx ); + + prev_total=ctx.dTotal; + prev_idle=ctx.dIdle; + + return 0; +} + +int devIocStatsGetCpuUsage (loadInfo *pval) +{ + + epics_cpu_usage_context ctx; + double total; + double idle; + double delta_total; + double delta_idle; + + ctx.dTotal=0; + ctx.dIdle=0; + ctx.uiThreads_cnt=0; + + rtems_task_iterate( epics_cpu_usage_visitor, &ctx ); + + total=ctx.dTotal; + idle=ctx.dIdle; + + if (total >= prev_total) { + delta_total = total - prev_total; + delta_idle = idle - prev_idle; + } else { + delta_total = total; + delta_idle = idle; + } + prev_total = total; + prev_idle = idle; + + + if (delta_idle > delta_total) + pval->cpuLoad = 0.0; + else + pval->cpuLoad = 100.0 - (delta_idle * 100.0 / delta_total); + + return 0; +} + +#else # if (__RTEMS_MAJOR__ > 4) \ || (__RTEMS_MAJOR__ == 4 && __RTEMS_MINOR__ > 7) typedef char objName[13]; @@ -103,7 +214,7 @@ static void cpu_ticks(double *total, double *idle) if (tc) { *total += CPU_ELAPSED_TIME(tc); RTEMS_OBJ_GET_NAME( tc, name ); - if (name[0]) { + if (name && name[0]) { if (name[0] == 'I' && name[1] == 'D' && name[2] == 'L' && name[3] == 'E') { *idle = CPU_ELAPSED_TIME(tc); @@ -154,3 +265,4 @@ int devIocStatsGetCpuUsage (loadInfo *pval) return 0; #endif } +#endif diff --git a/devIocStats/os/RTEMS/osdNetStats.c b/devIocStats/os/RTEMS/osdNetStats.c new file mode 100644 index 0000000..e4192df --- /dev/null +++ b/devIocStats/os/RTEMS/osdNetStats.c @@ -0,0 +1,116 @@ +#include + +/* #include +#include +#include +#include +#include +#include +#include +#include +#include +*/ +#include +#include +#include +#include +#include +#include +#include +#include +/*#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +*/ + +#include "devRtemsNetStats.h" + +/* This would otherwise need _KERNEL to be defined... */ +/* extern struct ipstat ipstat; +extern struct udpstat udpstat; +extern struct tcpstat tcpstat; */ /* tcp statistics */ +extern struct ifnet *ifnet; + + +int getPacketStats( void * ptNetHeadVoid){ + + struct ifnet *ifp; + struct tNetList *ptNetList=NULL; + struct tNetList *ptNetHead; + + ptNetHead=(struct tNetList *)ptNetHeadVoid; + + if(ptNetHead==NULL) + return NET_NOK; + /* printf ("************ INTERFACE STATISTICS ************\n"); */ + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + ptNetList=ptNetHead; + while(ptNetList){ + if(ptNetList->pcNetIf!=NULL){ + if(!strncmp(ifp->if_name,ptNetList->pcNetIf,strlen(ifp->if_name))){ + if(ifp->if_unit == atoi( &(ptNetList->pcNetIf[strlen(ifp->if_name)]) ) ){ + if(ptNetList->pData!=NULL){ + ((struct rtnl_link_stats *)(ptNetList->pData))->rx_packets=ifp->if_data.ifi_ipackets; + ((struct rtnl_link_stats *)(ptNetList->pData))->tx_packets=ifp->if_data.ifi_opackets; + ((struct rtnl_link_stats *)(ptNetList->pData))->rx_dropped=0; + ((struct rtnl_link_stats *)(ptNetList->pData))->tx_dropped=ifp->if_snd.ifq_drops; + ((struct rtnl_link_stats *)(ptNetList->pData))->rx_errors=ifp->if_data.ifi_ierrors; + ((struct rtnl_link_stats *)(ptNetList->pData))->tx_errors=ifp->if_data.ifi_oerrors; + ((struct rtnl_link_stats *)(ptNetList->pData))->collisions=ifp->if_data.ifi_collisions; + /* No Carrier : libchip/network/open_eth.c */ + /* ((struct rtnl_link_stats *)(ptNetList->pData))->tx_carrier_errors=ifp->if_softc->txLostCarrier; */ + ((struct rtnl_link_stats *)(ptNetList->pData))->tx_carrier_errors=0; + } + }/* if(ifp->if_unit != atoi( */ + }/*if(!strncmp(ifp->if_name,ptNetList->pc */ + }/* if(ptNetList->pcNetIf!=NULL){ */ + ptNetList=ptNetList->next; + }/* wile loop*/ + + /*rtems_bsdnet_semaphore_obtain (); + (*ifp->if_ioctl)(ifp, SIO_RTEMS_SHOW_STATS, NULL); + rtems_bsdnet_semaphore_release (); */ + + }/* for loop */ + + return NET_OK; +} + +int getIpAddr(char *pcIf,char **pcIfAddr){ + struct ifnet *ifp; + struct ifaddr *ifa; + char buf[17]; + /* printf ("************ INTERFACE STATISTICS ************\n"); */ + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + if(!strncmp(ifp->if_name,pcIf,strlen(ifp->if_name))){ + if(ifp->if_unit != atoi( &(pcIf[strlen(ifp->if_name)]) ) ) + continue; + }/* if(!strncmp(ifp->if_name */ + else + continue; + + for (ifa = ifp->if_addrlist ; ifa ; ifa = ifa->ifa_next) { + if ( !ifa->ifa_addr ) + continue; + if(ifa->ifa_addr->sa_family == AF_INET) { + if(inet_ntop (AF_INET, &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr, buf, sizeof(buf))){ + *pcIfAddr=malloc(sizeof(char)*(strlen(buf)+1)); + if(*pcIfAddr) + sprintf(*pcIfAddr,"%s",buf); /* copy IP address */ + } + } + } + /* rtems_bsdnet_semaphore_obtain (); + (*ifp->if_ioctl)(ifp, SIO_RTEMS_SHOW_STATS, NULL); + rtems_bsdnet_semaphore_release (); */ + } + return NET_OK; +} + diff --git a/devIocStats/os/RTEMS/osdSuspTasks.c b/devIocStats/os/RTEMS/osdSuspTasks.c index e875f57..350d7af 100644 --- a/devIocStats/os/RTEMS/osdSuspTasks.c +++ b/devIocStats/os/RTEMS/osdSuspTasks.c @@ -42,6 +42,27 @@ int devIocStatsInitSuspTasks (void) { return 0; } +# if (__RTEMS_MAJOR__ >= 5) +static bool epics_suspend_task_visitor( Thread_Control *the_thread, void *arg ) +{ + if ( (RTEMS_ALREADY_SUSPENDED == rtems_task_is_suspended( the_thread->Object.id )) ) { + (*(int *)arg)++; + } + return false; +} + + +int devIocStatsGetSuspTasks (int *pval) +{ + int n = 0; + rtems_task_iterate( epics_suspend_task_visitor, (void *)&n ); + + *pval = n; + return 0; +} + +#else + int devIocStatsGetSuspTasks (int *pval) { Objects_Control *o; @@ -61,3 +82,4 @@ int devIocStatsGetSuspTasks (int *pval) *pval = n; return 0; } +#endif diff --git a/devIocStats/os/RTEMS/osdWorkspaceUsage.c b/devIocStats/os/RTEMS/osdWorkspaceUsage.c index 3d0568d..bcb7495 100644 --- a/devIocStats/os/RTEMS/osdWorkspaceUsage.c +++ b/devIocStats/os/RTEMS/osdWorkspaceUsage.c @@ -38,9 +38,11 @@ int devIocStatsGetWorkspaceUsage (memInfo *pval) _Heap_Get_information( &_Workspace_Area, &info); /*_Heap_Get_information is part of the RTEMS API */ _RTEMS_Unlock_allocator(); #endif /* RTEMS_PROTECTED_HEAP */ -# if (__RTEMS_MAJOR__ > 4) \ +# if (__RTEMS_MAJOR__ >= 5) + pval->numBytesTotal = rtems_configuration_get_work_space_size(); +# elif (__RTEMS_MAJOR__ > 4) \ || (__RTEMS_MAJOR__ == 4 && __RTEMS_MINOR__ > 9) - pval->numBytesTotal = Configuration.work_space_size; + pval->numBytesTotal = Configuration.work_space_size; #else pval->numBytesTotal = _Configuration_Table->work_space_size; #endif diff --git a/devIocStats/os/WIN32/osdCpuUtilization.c b/devIocStats/os/WIN32/osdCpuUtilization.c index a36f304..75a9b23 100644 --- a/devIocStats/os/WIN32/osdCpuUtilization.c +++ b/devIocStats/os/WIN32/osdCpuUtilization.c @@ -23,7 +23,6 @@ #if defined(__MINGW32__) || defined(__MINGW64__) #define WINVER 0x0501 -#define _WIN32_WINNT 0x0601 #endif #include diff --git a/devIocStats/os/WIN32/osdMemUsage.c b/devIocStats/os/WIN32/osdMemUsage.c index fedebfc..97403ab 100644 --- a/devIocStats/os/WIN32/osdMemUsage.c +++ b/devIocStats/os/WIN32/osdMemUsage.c @@ -25,7 +25,6 @@ #if defined(__MINGW32__) || defined(__MINGW64__) #define WINVER 0x0501 -#define _WIN32_WINNT 0x0601 #endif #include diff --git a/devIocStats/os/default/osdNetStats.c b/devIocStats/os/default/osdNetStats.c new file mode 100644 index 0000000..304e76e --- /dev/null +++ b/devIocStats/os/default/osdNetStats.c @@ -0,0 +1,9 @@ +#include +int getPacketStats( void * ptNetHeadVoid){ + return NET_NOK; +} + +int getIpAddr(char *pcIf,char **pcIfAddr){ + return NET_NOK; +} + diff --git a/devIocStats/seqFunction.c b/devIocStats/seqFunction.c new file mode 100644 index 0000000..09535b1 --- /dev/null +++ b/devIocStats/seqFunction.c @@ -0,0 +1,15 @@ +#include + +#include +/* Dummy function which is used when sequencer is not used in the ioc */ +epicsShareFunc void seqGatherStats( + unsigned *seq_num_programs, + unsigned *seq_num_channels, + unsigned *seq_num_connected +){ + +*seq_num_programs=0; +*seq_num_channels=0; +*seq_num_connected=0; +} + diff --git a/iocAdmin/Db/Makefile b/iocAdmin/Db/Makefile index 0f8ecff..02b152a 100644 --- a/iocAdmin/Db/Makefile +++ b/iocAdmin/Db/Makefile @@ -11,20 +11,23 @@ include $(TOP)/configure/CONFIG # Create and install (or just install) # databases, templates, substitutions like this # -DB += ioc.db -DB += iocRTOS.db -DB += iocVxWorksOnly.db -DB += iocRTEMSOnly.db -DB += iocEnvVar.db -DB += iocCluster.db -DB += iocScanMon.db -DB += iocScanMonSum.db -DB += iocGeneralTime.db -DB += access.db -DB += iocAdminVxWorks.db -DB += iocAdminSoft.db -DB += iocAdminRTEMS.db -DB += iocAdminScanMon.db +#DB += ioc.db +#DB += iocRTOS.db +#DB += iocVxWorksOnly.db +#DB += iocRTEMSOnly.db +#DB += iocEnvVar.db +#DB += iocCluster.db +#DB += iocScanMon.db +#DB += iocScanMonSum.db +#DB += iocGeneralTime.db +#DB += access.db +#DB += iocAdminVxWorks.db +#DB += iocAdminSoft.db +#DB += iocAdminRTEMS.db +#DB += iocAdminScanMon.db +DB += ioc_stats.db +DB += ioc_NetStats.db +DB += sys_stats.db # #---------------------------------------------------- diff --git a/iocAdmin/Db/ioc_NetStats.db b/iocAdmin/Db/ioc_NetStats.db new file mode 100644 index 0000000..1dc41a7 --- /dev/null +++ b/iocAdmin/Db/ioc_NetStats.db @@ -0,0 +1,108 @@ +# Network Statistics related records +# example for INP_IF_NAME => eth0 + +record(stringin, "$(IOCNAME):NET_$(IF_NAME)") +{ + field(DESC,"IF $(INP_IF_NAME) IP address") + field(DTYP, "IOC net stats") + field(INP, "@netAddr:$(INP_IF_NAME)") + field(PINI, "YES") +} + +#--------------------------------------------------------- +#------------------- PACKETS_TX ------------------------ + +record(ai, "$(IOCNAME):NET_$(IF_NAME)_PACKETS_TX") { + field(DESC,"IF $(INP_IF_NAME) PACKETS_TX") + field(SCAN, "I/O Intr") + field(DTYP, "IOC net stats") + field(INP, "@netPacketsTx:$(INP_IF_NAME)") + field(FLNK, "$(IOCNAME):NET_$(IF_NAME)_PACKETS_TX_LAST") +} + +record(calc,"$(IOCNAME):NET_$(IF_NAME)_PACKETS_TX_LAST"){ + field(INPA,"$(IOCNAME):NET_$(IF_NAME)_PACKETS_TX") + field(INPB,"$(IOCNAME):NET_$(IF_NAME)_PACKETS_TX_PREV NMS") + field(CALC,"!B? 0:A-B") + field(FLNK,"$(IOCNAME):NET_$(IF_NAME)_PACKETS_TX_PREV") + info(archive,"VerySlow") +} + +record(ai, "$(IOCNAME):NET_$(IF_NAME)_PACKETS_TX_PREV") { + field(DESC,"Previous NET_$(IF_NAME)_PACKETS_TX") + field(INP, "$(IOCNAME):NET_$(IF_NAME)_PACKETS_TX") +} + +#--------------------------------------------------------- +#------------------- PACKETS_RX ------------------------ + +record(ai, "$(IOCNAME):NET_$(IF_NAME)_PACKETS_RX") { + field(DESC,"IF $(INP_IF_NAME) PACKETS_RX") + field(SCAN, "I/O Intr") + field(DTYP, "IOC net stats") + field(INP, "@netPacketsRx:$(INP_IF_NAME)") + field(FLNK, "$(IOCNAME):NET_$(IF_NAME)_PACKETS_RX_LAST") +} + +record(calc,"$(IOCNAME):NET_$(IF_NAME)_PACKETS_RX_LAST"){ + field(INPA,"$(IOCNAME):NET_$(IF_NAME)_PACKETS_RX") + field(INPB,"$(IOCNAME):NET_$(IF_NAME)_PACKETS_RX_PREV NMS") + field(CALC,"!B? 0:A-B") + field(FLNK,"$(IOCNAME):NET_$(IF_NAME)_PACKETS_RX_PREV") + info(archive,"VerySlow") +} + +record(ai, "$(IOCNAME):NET_$(IF_NAME)_PACKETS_RX_PREV") { + field(DESC,"Previous NET_$(IF_NAME)_PACKETS_RX") + field(INP, "$(IOCNAME):NET_$(IF_NAME)_PACKETS_RX") +} + + + + + + +#--------------------------------------------------------- + +record(ai, "$(IOCNAME):NET_$(IF_NAME)_ERRORS_TX") { + field(DESC,"IF $(INP_IF_NAME) ERRORS_TX") + field(SCAN, "I/O Intr") + field(DTYP, "IOC net stats") + field(INP, "@netPErrorTx:$(INP_IF_NAME)") + info(archive,"VerySlow") +} +record(ai, "$(IOCNAME):NET_$(IF_NAME)_ERRORS_RX") { + field(DESC,"IF $(INP_IF_NAME) ERRORS_RX") + field(SCAN, "I/O Intr") + field(DTYP, "IOC net stats") + field(INP, "@netPErrorRx:$(INP_IF_NAME)") + info(archive,"VerySlow") +} +record(ai, "$(IOCNAME):NET_$(IF_NAME)_DROPPED_TX") { + field(DESC,"IF $(INP_IF_NAME) DROPPED_TX") + field(SCAN, "I/O Intr") + field(DTYP, "IOC net stats") + field(INP, "@netPDroppedTx:$(INP_IF_NAME)") + info(archive,"VerySlow") +} +record(ai, "$(IOCNAME):NET_$(IF_NAME)_DROPPED_RX") { + field(DESC,"IF $(INP_IF_NAME) DROPPED_RX") + field(SCAN, "I/O Intr") + field(DTYP, "IOC net stats") + field(INP, "@netPDroppedRx:$(INP_IF_NAME)") + info(archive,"VerySlow") +} +record(ai, "$(IOCNAME):NET_$(IF_NAME)_COLLISIONS") { + field(DESC,"IF $(INP_IF_NAME) COLLISIONS") + field(SCAN, "I/O Intr") + field(DTYP, "IOC net stats") + field(INP, "@netPCollisions:$(INP_IF_NAME)") + info(archive,"VerySlow") +} +record(ai, "$(IOCNAME):NET_$(IF_NAME)_CARRIER_ERR") { + field(DESC,"IF $(INP_IF_NAME) CARRIER Error") + field(SCAN, "I/O Intr") + field(DTYP, "IOC net stats") + field(INP, "@netPCarrierErr:$(INP_IF_NAME)") + info(archive,"VerySlow") +} diff --git a/iocAdmin/Db/ioc_stats.db b/iocAdmin/Db/ioc_stats.db new file mode 100644 index 0000000..de5b654 --- /dev/null +++ b/iocAdmin/Db/ioc_stats.db @@ -0,0 +1,303 @@ +record(stringin, "$(IOCNAME):STARTTOD") +{ + field(DESC, "Time and date of startup") + field(DTYP, "Soft Timestamp") + field(PINI, "YES") + field(INP, "@%m/%d/%Y %H:%M:%S") + info(archive,"VerySlow") +} +record(calcout, "$(IOC):hb") +{ + field(DESC, "1 Hz counter since startup") + field(CALC, "(A<2147483647)?A+1:1") + field(SCAN, "1 second") + field(INPA, "$(IOC):hb") +} +alias("$(IOC):hb", "$(IOCNAME):hb") +record(sub, "$(IOC):exit") +{ + alias("$(IOCNAME):exit") + field(DESC, "IOC Restart" ) + field(SNAM, "rebootProc") + field(BRSV,"INVALID") + field(L,"1") +} +record(ai, "$(IOCNAME):CA_CLNT_CNT") { + field(DESC, "Number of CA Clients") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@ca_clients") + field(HOPR, "200") + field(HIHI, "175") + field(HIGH, "100") + field(HHSV, "MAJOR") + field(HSV, "MINOR") + info(archive, "VerySlow") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +} +record(ai, "$(IOCNAME):CA_CONN_CNT") { + field(DESC, "Number of CA Connections") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@ca_connections") + field(HOPR, "5000") + field(HIHI, "4500") + field(HIGH, "4000") + field(HHSV, "MAJOR") + field(HSV, "MINOR") + info(archive, "VerySlow") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +} +record(ai, "$(IOCNAME):CA_LCONN_CNT") { + field(DESC, "Number of CA links") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@ca_lconn") + field(HOPR, "5000") + field(HIHI, "4500") + #field(HIGH, "1") + field(HHSV, "MAJOR") + #field(HSV, "MAJOR") + info(archive, "VerySlow") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +} +record(ai, "$(IOCNAME):CA_LNCONN_CNT") { + field(DESC, "CA Links Not Conncted") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@ca_lnconn") + field(HOPR, "5000") + field(HIHI, "1") + #field(HIGH, "1") + field(HHSV, "MAJOR") + #field(HSV, "MAJOR") + info(archive, "VerySlow") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") + field(FLNK,"$(IOCNAME):CA_LNCONN_CNT_ACQ_CHECK") +} + +record(calcout,"$(IOCNAME):CA_LNCONN_CNT_ACQ_CHECK"){ + field(INPA,"$(IOCNAME):CA_LNCONN_CNT") + field(INPB,"$(IOCNAME):CA_LNCONN_CNT_ACQ") + field(CALC,"B > A && B>0? 1:0") + field(OOPT,"When Non-zero") + field(DOPT,"Use CALC") + field(OUT,"$(IOCNAME):CA_LNCONN_CNT_ACQ.PROC") + field(FLNK,"$(IOCNAME):IOC_HEALTH") +} + +record(ao,"$(IOCNAME):CA_LNCONN_CNT_ACQ"){ + field(DESC,"Acknowlege CA_LNCONN_CNT") + field(OMSL,"closed_loop") + field(DOL,"$(IOCNAME):CA_LNCONN_CNT") + field(FLNK,"$(IOCNAME):IOC_HEALTH") +} + +record(ai, "$(IOCNAME):CA_LDCONN_CNT") { + field(DESC, "CA Links Disconnected") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@ca_ldconn") + field(HOPR, "5000") + field(HIHI, "1") + #field(HIGH, "1") + field(HHSV, "MAJOR") + #field(HSV, "MINOR") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") + #field(FLNK,"$(IOCNAME):CA_LDCONN_CNT_ACQ_CHECK") +} + +# Removed by Tynan 7/13/22 +#record(calcout,"$(IOCNAME):CA_LDCONN_CNT_ACQ_CHECK"){ +# field(INPA,"$(IOCNAME):CA_LDCONN_CNT") +# field(INPB,"$(IOCNAME):CA_LDCONN_CNT_ACQ") +# field(CALC,"B > A && B>0? 1:0") +# field(OOPT,"When Non-zero") +# field(DOPT,"Use CALC") +# field(OUT,"$(IOCNAME):CA_LDCONN_CNT_ACQ.PROC") +#} + + +#record(ao,"$(IOCNAME):CA_LDCONN_CNT_ACQ"){ +# field(DESC,"Acknowlege CA_LDCONN_CNT") +# field(OMSL,"closed_loop") +# field(DOL,"$(IOCNAME):CA_LDCONN_CNT") +# field(FLNK,"$(IOCNAME):IOC_HEALTH") +#} + +record(ai, "$(IOCNAME):SEQ_PROG_CNT") { + field(DESC, "Number SEQ Programs") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@seq_prog") + field(HOPR, "5000") + field(HIHI, "4500") + #field(HIGH, "1") + field(HHSV, "MAJOR") + #field(HSV, "MINOR") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +} +record(ai, "$(IOCNAME):SEQ_PVS") { + field(DESC, "Number SEQ Programs PVs") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@seq_pvs") + field(HOPR, "5000") + field(HIHI, "4500") + #field(HIGH, "1") + field(HHSV, "MAJOR") + #field(HSV, "MINOR") + info(archive, "VerySlow") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +} +record(ai, "$(IOCNAME):SEQ_PVS_DCONN") { + field(DESC, "Nr of SEQ Disonnected PVs") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@seq_pvs_dconn") + field(HOPR, "5000") + field(HIHI, "1") + #field(HIGH, "1") + field(HHSV, "MAJOR") + #field(HSV, "MINOR") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") + info(archive, "VerySlow") + field(FLNK,"$(IOCNAME):SEQ_PVS_DCONN_ACQ_CHECK") +} + +record(calcout,"$(IOCNAME):SEQ_PVS_DCONN_ACQ_CHECK"){ + field(INPA,"$(IOCNAME):SEQ_PVS_DCONN") + field(INPB,"$(IOCNAME):SEQ_PVS_DCONN_ACQ") + field(CALC,"B > A && B>0? 1:0") + field(OOPT,"When Non-zero") + field(DOPT,"Use CALC") + field(OUT,"$(IOCNAME):SEQ_PVS_DCONN_ACQ.PROC") +} + +record(ao,"$(IOCNAME):SEQ_PVS_DCONN_ACQ"){ + field(DESC,"Acknowlege SEQ_PVS_DCONN") + field(OMSL,"closed_loop") + field(DOL,"$(IOCNAME):SEQ_PVS_DCONN") + field(FLNK,"$(IOCNAME):IOC_HEALTH") +} + +record(calc, "$(IOCNAME):IOC_HEALTH"){ + field(DESC, "IOC Healthy=1") + field(INPA,"$(IOCNAME):CA_LNCONN_CNT") + field(INPB,"$(IOCNAME):CA_LNCONN_CNT_ACQ") + field(INPC,"$(IOCNAME):SEQ_PVS_DCONN") + field(INPD,"$(IOCNAME):SEQ_PVS_DCONN_ACQ") + #field(INPE,"$(IOCNAME):CA_LDCONN_CNT") + #field(INPF,"$(IOCNAME):CA_LDCONN_CNT_ACQ") + #field(CALC,"A>B || C>D || E>F? 0:1") + field(CALC,"A>B || C>D? 0:1") + field(HOPR, "1") + field(LOLO, "0") + #field(HIGH, "1") + field(LLSV, "MAJOR") + #field(HSV, "MINOR") + info(archive,"Slow") +} + +#record(ai, "$(IOCNAME):IOC_HEALTH") { +# field(DESC, "IOC Healthy=1") +# field(SCAN, "I/O Intr") +# field(DTYP, "IOC stats") +# field(INP, "@ioc_health") +# field(HOPR, "1") +# field(LOLO, "0") +# #field(HIGH, "1") +# field(LLSV, "MAJOR") +# #field(HSV, "MINOR") +# info(archive,"policy:MonSparse") +# info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +#} + +record(ai, "$(IOCNAME):RECORD_CNT") { + field(DESC, "Number of Records") + field(PINI, "YES") + field(DTYP, "IOC stats") + field(INP, "@records") + info(archive,"VerySlow") +} +record(ai, "$(IOCNAME):IOC_CPU_LOAD") { + alias("$(IOCNAME):LOAD") + field(DESC, "IOC CPU Load") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@ioc_cpuload") + field(EGU, "%") + field(PREC, "1") + field(HOPR, "100") + field(HIHI, "80") + field(HIGH, "70") + field(HHSV, "MAJOR") + field(HSV, "MINOR") + info(archive,"VerySlow") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +} +record(stringin, "$(IOCNAME):HOSTNAME") { + field(DESC, "Host Name") + field(DTYP, "IOC stats") + field(INP, "@hostname") + field(PINI, "YES") +} +record(stringin, "$(IOCNAME):UPTIME") { + field(DESC, "Elapsed Time since Start") + field(SCAN, "1 second") + field(DTYP, "IOC stats") + field(INP, "@up_time") + field(PINI, "YES") +} +record(stringin, "$(IOCNAME):ENGINEER") { + field(DESC, "Engineer") + field(DTYP, "IOC stats") + field(INP, "@engineer") + field(PINI, "YES") +} +record(stringin, "$(IOCNAME):LOCATION") { + field(DESC, "Location") + field(DTYP, "IOC stats") + field(INP, "@location") + field(PINI, "YES") +} +record(stringin, "$(IOCNAME):WIKI") { + field(DESC, "https://controls.als.lbl.gov/adp/VAL") + field(DTYP, "IOC stats") + field(INP, "@wiki") + field(PINI, "YES") +} +record(ai, "$(IOCNAME):PROCESS_ID") { + field(DESC, "Process ID") + field(PINI, "YES") + field(DTYP, "IOC stats") + field(INP, "@proc_id") +} +record(ai, "$(IOCNAME):PARENT_ID") { + field(DESC, "Parent Process ID") + field(PINI, "YES") + field(DTYP, "IOC stats") + field(INP, "@parent_proc_id") +} +record(ai, "$(IOCNAME):MEM_USED") { + field(DESC, "Allocated Memory") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@allocated_bytes") + field(EGU, "byte") + info(archive,"VerySlow") +} +record(stringin, "$(IOCNAME):EPICS_VERS") { + field(DESC, "EPICS Version") + field(DTYP, "IOC stats") + field(INP, "@epics_ver") + field(PINI, "YES") +} +record(waveform, "$(IOCNAME):APP_DIR") { + field(DESC, "Application Directory") + field(DTYP, "IOC stats") + field(INP, "@pwd") + field(NELM, "160") + field(FTVL, "CHAR") + field(PINI, "YES") +} diff --git a/iocAdmin/Db/sys_stats.db b/iocAdmin/Db/sys_stats.db new file mode 100644 index 0000000..085d6c3 --- /dev/null +++ b/iocAdmin/Db/sys_stats.db @@ -0,0 +1,88 @@ +record(stringin, "$(IOCNAME):TOD") +{ + field(DESC, "Current time and date") + field(DTYP, "Soft Timestamp") + field(SCAN, "1 second") + field(INP, "@%m/%d/%Y %H:%M:%S") +} +record(ai, "$(IOCNAME):FD_MAX") { + field(DESC, "Max File Descriptors") + field(PINI, "YES") + field(DTYP, "IOC stats") + field(INP, "@maxfd") +} +record(ai, "$(IOCNAME):FD_CNT") { + field(DESC, "Allocated File Descriptors") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(FLNK, "$(IOCNAME):FD_FREE PP MS") + field(INP, "@fd") +} +record(calc, "$(IOCNAME):FD_FREE") { + field(DESC, "Available FDs") + field(CALC, "B>0?B-A:C") + field(INPA, "$(IOCNAME):FD_CNT NPP MS") + field(INPB, "$(IOCNAME):FD_MAX NPP MS") + field(INPC, "1000") + field(HOPR, "150") + field(LOLO, "5") + field(LOW, "20") + field(LLSV, "MAJOR") + field(LSV, "MINOR") + info(autosaveFields_pass0, "HOPR LOPR LOW LOLO LSV LLSV") +} +record(ai, "$(IOCNAME):SYS_CPU_LOAD") { + field(DESC, "System CPU Load") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@sys_cpuload") + field(EGU, "%") + field(PREC, "1") + field(HOPR, "100") + field(HIHI, "80") + field(HIGH, "70") + field(HHSV, "MAJOR") + field(HSV, "MINOR") + info(archive,"Slow") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +} +record(ai, "$(IOCNAME):CPU_CNT") { + field(DESC, "Number of CPUs") + field(DTYP, "IOC stats") + field(INP, "@no_of_cpus") + field(PINI, "YES") +} +record(ai, "$(IOCNAME):SUSP_TASK_CNT") { + field(DESC, "Number Suspended Tasks") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@suspended_tasks") + field(HIHI, "1") + field(HHSV, "MAJOR") + info(autosaveFields_pass0, "HOPR LOPR HIHI HIGH LOW LOLO HHSV HSV LSV LLSV") +} +record(ai, "$(IOCNAME):MEM_FREE") { + field(DESC, "Free Memory") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@free_bytes") + field(EGU, "byte") + field(LLSV, "MAJOR") + field(LSV, "MINOR") + info(archive,"Slow") + info(autosaveFields_pass0, "HOPR LOPR LOW LOLO LSV LLSV") +} +record(ai, "$(IOCNAME):MEM_MAX") { + field(DESC, "Maximum Memory") + field(SCAN, "I/O Intr") + field(DTYP, "IOC stats") + field(INP, "@total_bytes") + info(archive,"VerySlow") + field(EGU, "byte") +} +record(stringin, "$(IOCNAME):KERNEL_VERS") { + field(DESC, "Kernel Version") + field(DTYP, "IOC stats") + field(INP, "@kernel_ver") + field(PINI, "YES") +} diff --git a/iocBoot/ioctestIocNetStatsApp/Makefile b/iocBoot/ioctestIocNetStatsApp/Makefile new file mode 100644 index 0000000..e1b9aa4 --- /dev/null +++ b/iocBoot/ioctestIocNetStatsApp/Makefile @@ -0,0 +1,5 @@ +TOP = ../.. +include $(TOP)/configure/CONFIG +ARCH = $(EPICS_HOST_ARCH) +TARGETS = envPaths +include $(TOP)/configure/RULES.ioc diff --git a/iocBoot/ioctestIocNetStatsApp/st.cmd b/iocBoot/ioctestIocNetStatsApp/st.cmd new file mode 100755 index 0000000..d143154 --- /dev/null +++ b/iocBoot/ioctestIocNetStatsApp/st.cmd @@ -0,0 +1,27 @@ +#!../../bin/linux-x86_64/testIocNetStats + +## You may have to change testIocNetStats to something else +## everywhere it appears in this file + +< envPaths +epicsEnvSet("ENGINEER", "md23") +epicsEnvSet("LOCATION", "Home") +epicsEnvSet("WIKI", "TBD") +epicsEnvSet("IOCNAME", "netTest") + + +## Register all support components +dbLoadDatabase("../../dbd/testIocNetStats.dbd",0,0) +testIocNetStats_registerRecordDeviceDriver(pdbbase) + +## Load record instances +#dbLoadRecords("../../db/testIocNetStats.db","user=mirek") +dbLoadRecords("../../db/ioc_stats.db","IOCNAME=IOCTEST,IOC=IOC") +dbLoadRecords("../../db/ioc_NetStats.db","IOCNAME=IOCTEST,INP_IF_NAME=eth0,IF_NAME=LAN1") +dbLoadRecords("../../db/ioc_NetStats.db","IOCNAME=IOCTEST,INP_IF_NAME=lo,IF_NAME=LO") +#dbLoadRecords("../../db/ioc_NetStats.db","IOCNAME=IOCTEST,INP_IF_NAME=wlan0,IF_NAME=WLAN1") + +iocInit() + +## Start any sequence programs +#seq snctestIocNetStats,"user=mirek" diff --git a/testIocNetStatsApp/Db/Makefile b/testIocNetStatsApp/Db/Makefile new file mode 100644 index 0000000..983981d --- /dev/null +++ b/testIocNetStatsApp/Db/Makefile @@ -0,0 +1,22 @@ +TOP=../.. +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE + +#---------------------------------------------------- +# Optimization of db files using dbst (DEFAULT: NO) +#DB_OPT = YES + +#---------------------------------------------------- +# Create and install (or just install) into /db +# databases, templates, substitutions like this +#DB += xxx.db + +#---------------------------------------------------- +# If .db template is not named *.template add +# _template = + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/testIocNetStatsApp/Makefile b/testIocNetStatsApp/Makefile new file mode 100644 index 0000000..10e0126 --- /dev/null +++ b/testIocNetStatsApp/Makefile @@ -0,0 +1,8 @@ +TOP = .. +include $(TOP)/configure/CONFIG +DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*)) +DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*)) +DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*)) +DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*)) +include $(TOP)/configure/RULES_DIRS + diff --git a/testIocNetStatsApp/src/Makefile b/testIocNetStatsApp/src/Makefile new file mode 100644 index 0000000..cde7093 --- /dev/null +++ b/testIocNetStatsApp/src/Makefile @@ -0,0 +1,63 @@ +TOP=../.. + +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE +#============================= + +#============================= +# Build the IOC application + +PROD_IOC = testIocNetStats +# testIocNetStats.dbd will be created and installed +DBD += testIocNetStats.dbd + +# testIocNetStats.dbd will be made up from these files: +testIocNetStats_DBD += base.dbd +testIocNetStats_DBD += devIocStats.dbd + +# Include dbd files from all support applications: +#testIocNetStats_DBD += xxx.dbd + +# Add all the support libraries needed by this IOC +#testIocNetStats_LIBS += xxx + +# testIocNetStats_registerRecordDeviceDriver.cpp derives from testIocNetStats.dbd +testIocNetStats_SRCS += testIocNetStats_registerRecordDeviceDriver.cpp + +# Build the main IOC entry point on workstation OSs. +testIocNetStats_SRCS_DEFAULT += testIocNetStatsMain.cpp +testIocNetStats_SRCS_vxWorks += -nil- + +# Add support from base/src/vxWorks if needed +#testIocNetStats_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary +ifneq ($(SNCSEQ),) + # Build sncExample into testIocNetStatsSupport + testIocNetStats_LIBS += devIocStatsSeq + sncExample_SNCFLAGS += +r + testIocNetStats_DBD += sncExample.dbd + # A .stt sequence program is *not* pre-processed: + testIocNetStatsSupport_SRCS += sncExample.stt + testIocNetStatsSupport_LIBS += seq pv + testIocNetStats_LIBS += seq pv + + # Build sncProgram as a standalone program + PROD_HOST += sncProgram + sncProgram_SNCFLAGS += +m + # A .st sequence program *is* pre-processed: + sncProgram_SRCS += sncProgram.st + sncProgram_LIBS += seq pv + sncProgram_LIBS += $(EPICS_BASE_HOST_LIBS) +else + testIocNetStats_LIBS += devIocStats +endif + +# Finally link to the EPICS Base libraries +testIocNetStats_LIBS += $(EPICS_BASE_IOC_LIBS) + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/testIocNetStatsApp/src/testIocNetStatsMain.cpp b/testIocNetStatsApp/src/testIocNetStatsMain.cpp new file mode 100644 index 0000000..0914418 --- /dev/null +++ b/testIocNetStatsApp/src/testIocNetStatsMain.cpp @@ -0,0 +1,23 @@ +/* testIocNetStatsMain.cpp */ +/* Author: Marty Kraimer Date: 17MAR2000 */ + +#include +#include +#include +#include +#include + +#include "epicsExit.h" +#include "epicsThread.h" +#include "iocsh.h" + +int main(int argc,char *argv[]) +{ + if(argc>=2) { + iocsh(argv[1]); + epicsThreadSleep(.2); + } + iocsh(NULL); + epicsExit(0); + return(0); +}