PERFORCE change 81019 for review
Victor Cruceru
soc-victor at FreeBSD.org
Tue Jul 26 19:07:25 GMT 2005
http://perforce.freebsd.org/chv.cgi?CH=81019
Change 81019 by soc-victor at soc-victor_82.76.158.176 on 2005/07/26 19:07:03
1)Added support for periodic timers (beside the existent one-shot timers)
into the SNMP library (libbsnmp, -lbsnmp).
2)Adapted the instrumentation for hrProcessorTable so as the CPU load numbers
represent the average CPU load (per CPU) in the last minute ( via 4 samples per
minute ). This was implemented using a periodic timer.
3)Changed the implementation of hrDeviceTable so as the SNMP agent get the
device tree change notifications via /var/run/devd.pipe (if available).
This should reduce the overhead of scanning the system for device changes
to the minimum required.
Affected files ...
.. //depot/projects/soc2005/bsnmp/contrib/bsnmp/snmpd/main.c#2 edit
.. //depot/projects/soc2005/bsnmp/contrib/bsnmp/snmpd/snmpd.h#2 edit
.. //depot/projects/soc2005/bsnmp/contrib/bsnmp/snmpd/snmpmod.h#2 edit
.. //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile#13 edit
.. //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c#5 edit
.. //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c#3 edit
.. //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c#11 edit
.. //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h#15 edit
Differences ...
==== //depot/projects/soc2005/bsnmp/contrib/bsnmp/snmpd/main.c#2 (text+ko) ====
@@ -1621,21 +1621,27 @@
#endif
{
struct timer *tp = uap;
-
- LIST_REMOVE(tp, link);
+ if (tp->periodic == 0){
+ LIST_REMOVE(tp, link);
+ }
+
tp->func(tp->udata);
- free(tp);
+
+ if (tp->periodic == 0){
+ free(tp);
+ }
}
/*
* Start a timer
*/
void *
-timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod)
+timer_start(u_int ticks, u_int repeat_ticks, void (*func)(void *), void *udata, struct lmodule *mod)
{
struct timer *tp;
#ifndef USE_LIBBEGEMOT
struct timespec due;
+ struct timespec inter;
#endif
if ((tp = malloc(sizeof(struct timer))) == NULL) {
@@ -1646,21 +1652,26 @@
#ifndef USE_LIBBEGEMOT
due = evAddTime(evNowTime(),
evConsTime(ticks / 100, (ticks % 100) * 10000));
+ inter = evAddTime(evNowTime(),
+ evConsTime(repeat_ticks / 100, (ticks % 100) * 10000));
+
#endif
tp->udata = udata;
tp->owner = mod;
tp->func = func;
-
+ tp->periodic = (repeat_ticks == 0 ? 0 : 1); /*for clarity*/
+
LIST_INSERT_HEAD(&timer_list, tp, link);
#ifdef USE_LIBBEGEMOT
- if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) {
+ if ((tp->id = poll_start_timer( (repeat_ticks == 0 ? ticks * 10 : repeat_ticks * 10),
+ tp->periodic, tfunc, tp)) < 0) {
syslog(LOG_ERR, "cannot set timer: %m");
exit(1);
}
#else
- if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id)
+ if (evSetTimer(evctx, tfunc, tp, due, inter, &tp->id)
== -1) {
syslog(LOG_ERR, "cannot set timer: %m");
exit(1);
==== //depot/projects/soc2005/bsnmp/contrib/bsnmp/snmpd/snmpd.h#2 (text+ko) ====
@@ -92,6 +92,8 @@
void *udata; /* user data */
evTimerID id; /* timer id */
struct lmodule *owner; /* owner of the timer */
+ int periodic; /* flag to track periodic timers, 0 for one shot,
+ 1 for periodic timers*/
LIST_ENTRY(timer) link;
};
==== //depot/projects/soc2005/bsnmp/contrib/bsnmp/snmpd/snmpmod.h#2 (text+ko) ====
@@ -300,7 +300,7 @@
/*
* Timers.
*/
-void *timer_start(u_int, void (*)(void *), void *, struct lmodule *);
+void *timer_start(u_int, u_int ,void (*)(void *), void *, struct lmodule *);
void timer_stop(void *);
/*
==== //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile#13 (text+ko) ====
==== //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_device_tbl.c#5 (text+ko) ====
@@ -36,6 +36,11 @@
#include <assert.h>
#include <stdlib.h>
#include <err.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <errno.h>
/*just a prototype*/
int hr_device_collector(struct devinfo_dev *dev, void *arg);
@@ -289,7 +294,7 @@
struct hrDeviceTblEntry *entry = NULL, *entry_tmp = NULL;
- if ( this_tick <= hrState_g.hr_device_tick) {
+ if ( hrState_g.devd_sock < 0 && this_tick <= hrState_g.hr_device_tick) {
HR_DPRINTF((stderr, "%s: no refresh needed\n ",__func__));
return;
}
@@ -341,6 +346,65 @@
}
+int create_devd_socket(void) {
+ static const char devd_pipe_name[]="/var/run/devd.pipe";
+ int d_sock = -1;
+ struct sockaddr_un devd_addr;
+
+ bzero(&devd_addr, sizeof(struct sockaddr_un));
+
+ if ((d_sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR,"Failed to create the socket for %s: %m", devd_pipe_name);
+ return (-1);
+ }
+
+ devd_addr.sun_family = PF_LOCAL;
+ strlcpy(devd_addr.sun_path, devd_pipe_name, sizeof(devd_addr.sun_path) - 1);
+
+ if (connect(d_sock, (struct sockaddr *)&devd_addr,
+ sizeof(struct sockaddr_un)) == -1) {
+ syslog(LOG_ERR,"Failed to connect the socket for %s: %m", devd_pipe_name);
+ if (close(d_sock) < 0 ){
+ syslog(LOG_ERR,"Failed to close the socket for %s: %m", devd_pipe_name);
+ }
+ return (-1);
+ }
+
+ return d_sock;
+}
+
+void devd_socket_callback(int fd , void* arg __unused) {
+ char buf[512];
+ int read_len = -1;
+ assert(fd == hrState_g.devd_sock);
+ HR_DPRINTF((stderr, "__hrDeviceTable__ %s: called\n ", __func__));
+ read_len = read(fd, buf, sizeof(buf) - 1);
+ if (read_len < 0) {
+ if(errno == EBADF){
+ hrState_g.devd_sock = -1;
+ if (hrState_g.devd_fd != NULL) {
+ fd_deselect(hrState_g.devd_fd);
+ hrState_g.devd_fd = NULL;
+ }
+ syslog(LOG_ERR,"Closing devd_fd, revert to devinfo polling");
+ }
+
+ } else if (read_len == 0) {
+ syslog(LOG_ERR,"zero bytes read from devd pipe....");
+ } else {
+ switch(buf[0]){
+ case '+':
+ case '-':
+ case '?':
+ refresh_hrDevice_tbl_v();
+ return;
+ default:
+ syslog(LOG_ERR,"unknown message read from devd socket");
+
+ }
+ }
+}
+
/*
* This is the implementation for a generated (by a SNMP tool)
* function prototype, see hostres_tree.h
@@ -359,7 +423,8 @@
/*
refresh entries here?!
*/
- if ( (time(NULL) - hrState_g.hrDevice_tbl_age) > HR_DEVICE_TBL_REFRESH ) {
+ if ( hrState_g.devd_sock < 0 &&
+ (time(NULL) - hrState_g.hrDevice_tbl_age) > HR_DEVICE_TBL_REFRESH ) {
HR_DPRINTF((stderr, "__hrDeviceTable__ %s: need refresh\n ", __func__));
refresh_hrDevice_tbl_v();
}
==== //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_processor_tbl.c#3 (text+ko) ====
@@ -43,6 +43,20 @@
#include <sys/user.h>
#include <math.h>
+static
+int get_avg_load( struct hrProcessorTblEntry *entry ) {
+ int i = 0;
+ double sum = 0.0;
+ assert(entry != NULL);
+ for( i = 0; i < MAX_CPU_SAMPLES; i++ ){
+ sum += entry->samples[i];
+ }
+ return floor((double)sum/(double)MAX_CPU_SAMPLES);
+
+
+}
+
+
static
struct hrProcessorTblEntry *
hrProcessorTblEntry_find_by_cpu_no(u_char cpu_no) {
@@ -119,6 +133,9 @@
entry = hrProcessorTblEntry_find_by_cpu_no(kp->ki_lastcpu);
assert(entry != NULL); /*what? FIX ME!*/
+ if (entry == NULL) {
+ continue;
+ }
entry->idle_pid = kp->ki_pid;
@@ -128,7 +145,10 @@
entry->idle_pid));
- entry->load = floor((double)100.0 - hrProcessor_getpcpu(kp));
+ entry->samples[entry->cur_sample_idx] = (double)100.0 - hrProcessor_getpcpu(plist);
+ /*this is fisrt time, thus no previous samples*/
+ entry->load = floor(entry->samples[entry->cur_sample_idx]);
+ entry->cur_sample_idx = (entry->cur_sample_idx + 1) % MAX_CPU_SAMPLES;
}
@@ -175,6 +195,7 @@
entry->cpu_no = (u_char)cpu_no;
entry->idle_pid = 0;
entry->frwId = oid_zeroDotZero; /*unknown id - FIX ME*/
+
INSERT_OBJECT_INT(entry, &hrState_g.hr_processor_tbl);
hrState_g.detected_processor_count++;
@@ -188,7 +209,7 @@
HR_DPRINTF((stderr, "%s: %d CPUs detected\n", __func__,
hrState_g.detected_processor_count));
- hrProcessor_get_pids_v();
+ hrProcessor_get_pids_v();
}
@@ -245,6 +266,12 @@
}
+void get_cpus_samples(void* arg __unused) {
+
+ HR_DPRINTF((stderr, "[hrProcessorTable] [%llu]: ENTER\n ", get_ticks()));
+ refresh_hrProcessor_tbl_v();
+ HR_DPRINTF((stderr, "[hrProcessorTable] [%llu]: EXIT\n ", get_ticks() ));
+}
void refresh_hrProcessor_tbl_v(void) {
@@ -273,7 +300,9 @@
need_pids = 1;
continue;
}
- entry->load = floor((double)100.0 - hrProcessor_getpcpu(plist));
+ entry->samples[entry->cur_sample_idx] = (double)100.0 - hrProcessor_getpcpu(plist);
+ entry->load = get_avg_load(entry);
+ entry->cur_sample_idx = (entry->cur_sample_idx + 1) % MAX_CPU_SAMPLES;
}
if (need_pids == 1) {
@@ -295,14 +324,6 @@
struct hrProcessorTblEntry *entry = NULL;
int ret = SNMP_ERR_NOERROR;
- if ( (time(NULL) - hrState_g.hrProcessor_tbl_age) > HR_PROCESSOR_TBL_REFRESH ) {
- HR_DPRINTF((stderr, "__hrProcessorTable__ %s: need refresh\n ", __func__));
- refresh_hrProcessor_tbl_v();
- }
-
-
-
-
switch (curr_op) {
case SNMP_OP_GETNEXT:
==== //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.c#11 (text+ko) ====
@@ -37,6 +37,7 @@
#include <paths.h>
#include <string.h>
#include <stdlib.h>
+#include <unistd.h>
/*internal id got after we'll register this module with the agent */
@@ -129,7 +130,7 @@
hrState_g.hrFS_tbl_age = 0;
hrState_g.hrSWRun_tbl_age = 0;
hrState_g.hrDevice_tbl_age = 0;
- hrState_g.hrProcessor_tbl_age = 0;
+
init_hrStorage_tbl_v();
init_hrFS_tbl_v();
@@ -137,9 +138,26 @@
support is initialized here */
init_hrDevice_tbl_v();
init_hrProcessor_tbl_v();
-
- HR_DPRINTF((stderr, "[%s] done.\n", __func__));
+
+ /*
+ * Start the cpu stats collector
+ * The semantics of timer_start parameters is in "SNMP ticks";
+ * we have 100 "SNMP ticks" per second, thus we are trying below
+ * to get MAX_CPU_SAMPLES per minute
+ */
+
+ hrState_g.cpus_load_timer =
+ timer_start(100, 100*60/MAX_CPU_SAMPLES, get_cpus_samples, NULL, mod);
+
+
+ if ((hrState_g.devd_sock = create_devd_socket()) < 0) {
+ HR_DPRINTF((stderr, "Failed to create the socket to devd pipe.\n"));
+ }
+
+ hrState_g.devd_fd = NULL;
+
+ HR_DPRINTF((stderr, "[%s] done.\n", __func__));
return (0);
}
@@ -151,6 +169,20 @@
static
int hostres_fini(void)
{
+ if (hrState_g.cpus_load_timer != NULL) {
+ timer_stop(hrState_g.cpus_load_timer);
+ hrState_g.cpus_load_timer = NULL;
+ }
+
+ if (hrState_g.devd_fd != NULL) {
+ fd_deselect(hrState_g.devd_fd);
+ hrState_g.devd_fd = NULL;
+ }
+
+ if (hrState_g.devd_sock > 0) {
+ close(hrState_g.devd_sock);
+ }
+
/* here I free the resources used by this module*/
if( hrState_g.utmp_fp != (FILE*)NULL ) {
if( fclose(hrState_g.utmp_fp) != 0 ) {
@@ -194,7 +226,7 @@
hrState_g.hrFS_tbl_age = 0;
hrState_g.hrSWRun_tbl_age = 0;
hrState_g.hrDevice_tbl_age = 0;
- hrState_g.hrProcessor_tbl_age = 0;
+
hrState_g.dev_root = NULL;
@@ -230,17 +262,12 @@
HR_DPRINTF((stderr, "%s: hrSWRunTable needs refresh\n ", __func__));
refresh_hrSWRun_tbl_v();
}
-
+/*
if ( (time(NULL) - hrState_g.hrDevice_tbl_age) > HR_DEVICE_TBL_REFRESH ) {
HR_DPRINTF((stderr, "%s: hrDeviceTable needs refresh\n ", __func__));
refresh_hrDevice_tbl_v();
}
-
- if ( (time(NULL) - hrState_g.hrProcessor_tbl_age) > HR_PROCESSOR_TBL_REFRESH ) {
- HR_DPRINTF((stderr, "%s: hrProcessorTable needs refresh\n ", __func__));
- refresh_hrProcessor_tbl_v();
- }
-
+*/
HR_DPRINTF((stderr, "[%s] done.\n ", __func__));
}
@@ -288,6 +315,13 @@
host_registration_id = or_register(&oid_host,
"The MIB module for host resource mib (rfc 2790).",
hostres_module);
+
+ if (hrState_g.devd_sock > 0) {
+ hrState_g.devd_fd = fd_select(hrState_g.devd_sock, devd_socket_callback, NULL, hostres_module);
+ if (hrState_g.devd_fd == NULL) {
+ syslog(LOG_ERR, "fd_select failed on devd socket: %m");
+ }
+ }
HR_DPRINTF((stderr, "[%s] done.\n ", __func__));
}
==== //depot/projects/soc2005/bsnmp/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_snmp.h#15 (text+ko) ====
@@ -195,11 +195,18 @@
TAILQ_HEAD(swrun_tbl, hrSWRunTblEntry);
/*
+ * The number of CPU load samples per one minute,
+ * per each CPU
+ */
+#define MAX_CPU_SAMPLES 4
+
+/*
* This structure is used to hold a SNMP table entry
* for HOST-RESOURCES-MIB's hrProcessorTable
* Note that index is external being allocated & mainatined
* by the hrDeviceTable code.
*/
+
struct hrProcessorTblEntry {
int32_t index;
struct asn_oid frwId;
@@ -207,7 +214,11 @@
TAILQ_ENTRY(hrProcessorTblEntry) link;
/*not from SNMP table definition, only used internally*/
u_char cpu_no; /*which cpu, counted from 0*/
- pid_t idle_pid; /*the PID of ide process for this CPU */
+ pid_t idle_pid; /*the PID of idle process for this CPU */
+ double samples[MAX_CPU_SAMPLES]; /*the samples from the last
+ minutes, as required by MIB*/
+ uint32_t cur_sample_idx; /*current sample to fill in next time,
+ must be < MAX_CPU_SAMPLES*/
};
TAILQ_HEAD(processor_tbl, hrProcessorTblEntry);
@@ -333,6 +344,8 @@
struct
devinfo_dev *dev_root;
+ int devd_sock; /*socket for /var/run/devd.pipe*/
+ void *devd_fd; /*used to wait notifications from /var/run/devd.pipe */
/*
* next items are used for hrProcessorTable
*/
@@ -343,8 +356,9 @@
fixpt_t ccpu; /* kernel _ccpu variable */
int fscale; /* kernel _fscale variable */
- time_t hrProcessor_tbl_age;
+
uint64_t hr_processor_tick; /*last (agent) tick when hrProcessorTable was updated */
+ void* cpus_load_timer; /*periodic time used to get cpu laod stats*/
};
@@ -478,6 +492,20 @@
void refresh_hrDevice_tbl_v(void);
/*
+ * Creates the sockect to devd pipe, aka
+ * /var/run/devd.pipe. Returs the socket descriptor or
+ * -1 in case of an error
+ */
+int create_devd_socket(void);
+
+/*
+ * Callback for fd_select function; called when
+ * device events are detected in order to trigger
+ * a device table refresh
+ */
+void devd_socket_callback(int, void*);
+
+/*
* Init the things for hrProcessorTable
*/
void init_hrProcessor_tbl_v(void);
@@ -500,5 +528,10 @@
*/
void refresh_hrProcessor_tbl_v(void);
+/*
+ * The timer function used to collect the CPUs load samples
+ * Each CPU is "visited" MAX_CPU_SAMPLES times per one minute
+ */
+void get_cpus_samples(void*);
#endif /*__HOSTRES_SNMP_H_INCLUDED__ */
More information about the p4-projects
mailing list