vmstat_aix4.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:17k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * AIX4/5 cpu statistics module for net-snmp
  3.  *
  4.  * Version 0.1 - Initial release - 05/Jun/2003
  5.  *
  6.  * Derived from vmstat_solaris2.c
  7.  * Using libperfstat for statistics (Redbook SG24-6039)
  8.  *
  9.  * Ported to AIX by Michael Kukat <michael.kukat@to.com>
  10.  * Thinking Objects Software GmbH
  11.  * Lilienthalstra遝 2
  12.  * 70825 Stuttgart-Korntal
  13.  * http://www.to.com/
  14.  *
  15.  * Thanks go to Jochen Kmietsch for the solaris2 support and
  16.  * to DaimlerChrysler AG Stuttgart for making this port possible
  17.  */
  18. /*
  19.  * To make lint skip the debug code and stop complaining 
  20.  */
  21. #ifdef __lint
  22. #define SNMP_NO_DEBUGGING 1
  23. #endif
  24. /*
  25.  * Includes start here 
  26.  */
  27. /*
  28.  * Standard includes 
  29.  */
  30. #include <stdlib.h>
  31. #include <unistd.h>
  32. #include <sys/types.h>
  33. #include <sys/time.h>
  34. #include <string.h>
  35. /*
  36.  * libperfstat structs 
  37.  */
  38. #include <libperfstat.h>
  39. #include <net-snmp/net-snmp-config.h>
  40. #include <net-snmp/net-snmp-includes.h>
  41. #include <net-snmp/agent/net-snmp-agent-includes.h>
  42. #include "mibdefs.h"
  43. #include "util_funcs.h"
  44. /*
  45.  * Header file for this module 
  46.  */
  47. #include "vmstat.h"
  48. #include "vmstat_aix4.h"
  49. /*
  50.  * Includes end here 
  51.  */
  52. /*
  53.  * Global structures start here 
  54.  */
  55. /*
  56.  * A structure to save data gathered from the libperfstat.
  57.  */
  58. struct cpu_stat_snapshot {
  59. unsigned long long css_time;
  60. unsigned int    css_cpus;
  61. unsigned long long css_swapin;
  62. unsigned long long css_swapout;
  63. unsigned long long css_blocks_read;
  64. unsigned long long css_blocks_write;
  65. unsigned long long css_interrupts;
  66. unsigned long long css_context_sw;
  67. unsigned long long css_cpu[CPU_STATES];
  68. };
  69. /*
  70.  * Global structures end here 
  71.  */
  72. /*
  73.  * Global variables start here 
  74.  */
  75. /*
  76.  * Variables for the calculated values, filled in update_stats
  77.  * Need to be global since we need them in more than one function 
  78.  */
  79. static ulong swapin;
  80. static ulong swapout;
  81. static ulong blocks_read;
  82. static ulong blocks_write;
  83. static ulong interrupts;
  84. static ulong context_sw;
  85. /*
  86.  * Since MIB wants CPU_SYSTEM, which is CPU_KERNEL + CPU_WAIT 
  87.  */
  88. static long  cpu_perc[CPU_STATES];
  89. /*
  90.  * How many snapshots we have already taken, needed for the first 
  91.  * POLL_INTERVAL * POLL_VALUES seconds of agent running 
  92.  */
  93. static unsigned int number_of_snapshots;
  94. /*
  95.  * The place to store the snapshots of system data in 
  96.  */
  97. static struct cpu_stat_snapshot snapshot[POLL_VALUES + 1];
  98. /*
  99.  * And one for the raw counters, which we fill when the raw values are 
  100.  * requested, as opposed to the absolute values, which are taken every 
  101.  * POLL_INTERVAL seconds and calculated over POLL_INTERVAL * POLL_VALUES time 
  102.  */
  103. static struct cpu_stat_snapshot raw_values;
  104. /*
  105.  * Global variables end here 
  106.  */
  107. /*
  108.  * Functions start here 
  109.  */
  110. /*
  111.  * Function prototype 
  112.  */
  113. static void update_stats(unsigned int registrationNumber, void *clientarg);
  114. static int take_snapshot(struct cpu_stat_snapshot *css);
  115. /*
  116.  * init_vmstat_aix4 starts here 
  117.  * Init function for this module, from prototype 
  118.  * Defines variables handled by this module, defines root OID for 
  119.  * this module and registers it with the agent 
  120.  */
  121. FindVarMethod var_extensible_vmstat;
  122. void
  123. init_vmstat_aix4(void)
  124. {
  125. /*
  126.  * Which variables do we service ? 
  127.  */
  128. struct variable2 extensible_vmstat_variables[] = {
  129. {MIBINDEX, ASN_INTEGER, RONLY, var_extensible_vmstat, 1,
  130.  {MIBINDEX}},
  131. {ERRORNAME, ASN_OCTET_STR, RONLY, var_extensible_vmstat, 1,
  132.  {ERRORNAME}},
  133. {SWAPIN, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {SWAPIN}},
  134. {SWAPOUT, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {SWAPOUT}},
  135. {IOSENT, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {IOSENT}},
  136. {IORECEIVE, ASN_INTEGER, RONLY, var_extensible_vmstat, 1,
  137.  {IORECEIVE}},
  138. {SYSINTERRUPTS, ASN_INTEGER, RONLY, var_extensible_vmstat, 1,
  139.  {SYSINTERRUPTS}},
  140. {SYSCONTEXT, ASN_INTEGER, RONLY, var_extensible_vmstat, 1,
  141.  {SYSCONTEXT}},
  142. {CPUUSER, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {CPUUSER}},
  143. {CPUSYSTEM, ASN_INTEGER, RONLY, var_extensible_vmstat, 1,
  144.  {CPUSYSTEM}},
  145. {CPUIDLE, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {CPUIDLE}},
  146. {CPURAWUSER, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  147.  {CPURAWUSER}},
  148. {CPURAWSYSTEM, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  149.  {CPURAWSYSTEM}},
  150. {CPURAWIDLE, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  151.  {CPURAWIDLE}},
  152. {CPURAWWAIT, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  153.  {CPURAWWAIT}},
  154. {CPURAWKERNEL, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  155.  {CPURAWKERNEL}},
  156. {IORAWSENT, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  157.  {IORAWSENT}},
  158. {IORAWRECEIVE, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  159.  {IORAWRECEIVE}},
  160. {SYSRAWINTERRUPTS, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  161.  {SYSRAWINTERRUPTS}},
  162. {SYSRAWCONTEXT, ASN_COUNTER, RONLY, var_extensible_vmstat, 1,
  163.  {SYSRAWCONTEXT}},
  164. /*
  165.  * Future use: 
  166.  * {ERRORFLAG, ASN_INTEGER, RONLY, var_extensible_vmstat, 1, {ERRORFLAG }},
  167.  * {ERRORMSG, ASN_OCTET_STR, RONLY, var_extensible_vmstat, 1, {ERRORMSG }}
  168.  */
  169. };
  170. /*
  171.  * Define the OID pointer to the top of the mib tree that we're 
  172.  * registering underneath 
  173.  */
  174. oid  vmstat_variables_oid[] = { UCDAVIS_MIB, 11 };
  175. /*
  176.  * register ourselves with the agent to handle our mib tree 
  177.  * LINTED Trust me, I know what I'm doing 
  178.  */
  179. REGISTER_MIB("ucd-snmp/vmstat", extensible_vmstat_variables, variable2,
  180.  vmstat_variables_oid);
  181. /*
  182.  * Start with some useful data 
  183.  */
  184. update_stats(0, NULL);
  185. /*
  186.  * update_stats is run every POLL_INTERVAL seconds using this routine 
  187.  * (see 'man snmp_alarm') 
  188.  * This is only executed once to get some useful data in the beginning 
  189.  */
  190. if (snmp_alarm_register(5, NULL, update_stats, NULL) == 0) {
  191. snmp_log(LOG_WARNING,
  192.  "vmstat_aix4 (init): snmp_alarm_register failed.n");
  193. }
  194. /*
  195.  * This is the one that runs update_stats every POLL_INTERVAL seconds 
  196.  */
  197. if (snmp_alarm_register(POLL_INTERVAL, SA_REPEAT, update_stats, NULL)
  198. == 0) {
  199. snmp_log(LOG_ERR,
  200.  "vmstat_aix4 (init): snmp_alarm_register failed, cannot service requests.n");
  201. }
  202. } /* init_vmstat_aix4 ends here */
  203. /*
  204.  * Data collection function take_snapshot starts here 
  205.  * Get data from kernel and save into the snapshot strutcs 
  206.  * Argument is the snapshot struct to save to. Global anyway, but looks nicer 
  207.  */
  208. static int
  209. take_snapshot(struct cpu_stat_snapshot *css)
  210. {
  211. /*
  212.  * Variables start here 
  213.  */
  214. /*
  215.  * High resolution time counter 
  216.  */
  217. struct timeval tp;
  218. unsigned long long current_time;
  219. /*
  220.  * see libperfstat.h, holds CPU/memory data 
  221.  */
  222. perfstat_cpu_total_t cs;
  223. perfstat_memory_total_t ms;
  224. /*
  225.  * The usual stuff to count on, err, by 
  226.  */
  227. int i;
  228. /*
  229.  * Variables end here 
  230.  */
  231. /*
  232.  * Function starts here 
  233.  */
  234. /*
  235.  * Get time 
  236.  */
  237. gettimeofday(&tp, (struct timezone *)NULL);
  238. current_time = tp.tv_sec * (unsigned long long)1000000 + tp.tv_usec;
  239. /*
  240.  * If we have just gotten the data, return the values from last run (skip if-clause) 
  241.  * This happens on a snmpwalk request.  No need to read the perfstat again 
  242.  * if we just did it less than 2 seconds ago 
  243.  * Jumps into if-clause either when snapshot is empty or when too old 
  244.  */
  245. if ((css->css_time == 0)
  246. || (current_time > css->css_time + 2000000)) {
  247. /*
  248.  * Make sure we clean up before we put new data into snapshot 
  249.  */
  250. memset(css, 0, sizeof *css);
  251. /*
  252.  * Update timer 
  253.  */
  254. css->css_time = current_time;
  255. if((perfstat_cpu_total((perfstat_id_t *)NULL, &cs, sizeof(perfstat_cpu_total_t), 1) > 0) &&
  256. (perfstat_memory_total((perfstat_id_t *)NULL, &ms, sizeof(perfstat_memory_total_t), 1) > 0)) {
  257. css->css_cpus = cs.ncpus;
  258. css->css_swapin = ms.pgspins;
  259. css->css_swapout = ms.pgspouts;
  260. css->css_blocks_read = cs.sysread;
  261. css->css_blocks_write = cs.syswrite;
  262. css->css_interrupts = cs.devintrs + cs.softintrs;
  263. css->css_context_sw = cs.pswitch;
  264. css->css_cpu[CPU_USER] = cs.user;
  265. css->css_cpu[CPU_SYSTEM] = cs.sys;
  266. css->css_cpu[CPU_IDLE] = cs.idle;
  267. css->css_cpu[CPU_WAIT] = cs.wait;
  268. }
  269. }
  270. /*
  271.  * All engines running at warp speed, no problems (if there are any engines, that is) 
  272.  */
  273. return (cs.ncpus > 0 ? 0 : -1);
  274. } /* take_snapshot ends here */
  275. /*
  276.  * This gets called every POLL_INTERVAL seconds to update the snapshots.
  277.  * It takes a new snapshot and drops the oldest one.  This way we move
  278.  * the time window so we always take the values over 
  279.  * POLL_INTERVAL * POLL_VALUES seconds and update the data used every
  280.  * POLL_INTERVAL seconds 
  281.  * The alarm timer is in the init function of this module (snmp_alarm_register) 
  282.  */
  283. /*
  284.  * ARGSUSED0 
  285.  */
  286. static void
  287. update_stats(unsigned int registrationNumber, void *clientarg)
  288. {
  289. /*
  290.  * The time between the samples we compare 
  291.  */
  292. unsigned long long time_diff;
  293. /*
  294.  * Easier to use these than the snapshots, short hand pointers 
  295.  */
  296. struct cpu_stat_snapshot *css_old, *css_new;
  297. /*
  298.  * The usual stuff to count on, err, by 
  299.  */
  300. int  i;
  301. /*
  302.  * The sum of the CPU ticks that have passed on the different CPU states, so we can calculate 
  303.  * the percentages of each state 
  304.  */
  305. unsigned long long cpu_sum = 0;
  306. DEBUGMSGTL(("ucd-snmp/vmstat_aix4.c:update_stats",
  307. "updating statsn"));
  308. /*
  309.  * Take the current snapshot 
  310.  */
  311. if (take_snapshot(&snapshot[0]) == -1) {
  312. snmp_log(LOG_WARNING,
  313.  "vmstat_aix4 (update_stats): Something went wrong with take_snapshot.n");
  314. return;
  315. }
  316. /*
  317.  * Do we have some data we can use ?  An issue right after the start of the agent 
  318.  */
  319. if (number_of_snapshots > 0) {
  320. /*
  321.  * Huh, the number of CPUs changed during run time.  That is indeed s.th. worth noting, we 
  322.  * output a humorous (more or less) syslog message and need to retake the snapshots 
  323.  */
  324. if (snapshot[0].css_cpus != snapshot[1].css_cpus) {
  325. if (snapshot[0].css_cpus > snapshot[1].css_cpus) {
  326. snmp_log(LOG_NOTICE,
  327.  "vmstat_aix4 (update_stats): Cool ! Number of CPUs increased, must be hot-pluggable.n");
  328. } else {
  329. snmp_log(LOG_NOTICE,
  330.  "vmstat_aix4 (update_stats): Lost at least one CPU, RIP.n");
  331. }
  332. /*
  333.  * Make all snapshots but the current one invalid 
  334.  */
  335. number_of_snapshots = 1;
  336. /*
  337.  * Move the current one in the "first" [1] slot 
  338.  */
  339. memmove(&snapshot[1], &snapshot[0], sizeof snapshot[0]);
  340. /*
  341.  * Erase the current one 
  342.  */
  343. memset(&snapshot[0], 0, sizeof snapshot[0]);
  344. /*
  345.  * Try to get a new snapshot in five seconds so we can return s.th. useful 
  346.  */
  347. if (snmp_alarm_register(5, NULL, update_stats, NULL) == 0) {
  348. snmp_log(LOG_WARNING,
  349.  "vmstat_aix4 (update_stats): snmp_alarm_register failed.n");
  350. }
  351. return;
  352. }
  353. /*
  354.  * Short hand pointers 
  355.  */
  356. css_new = &snapshot[0];
  357. css_old = &snapshot[number_of_snapshots];
  358. /*
  359.  * How much time has passed between the snapshots we get the values from ? 
  360.  */
  361. time_diff =
  362. (snapshot[0].css_time -
  363.  snapshot[number_of_snapshots].css_time) / 1000;
  364. DEBUGMSGTL(("ucd-snmp/vmstat_aix4.c:update_stats",
  365. "time_diff: %lldn", time_diff));
  366. /*
  367.  * swapin and swapout are in pages, MIB wants kB/s,so we just need to get kB and seconds 
  368.  * For the others we need to get value per second 
  369.  * getpagesize() returns pagesize in bytes 
  370.  */
  371. /*
  372.  * LINTED cast needed, really 
  373.  */
  374. swapin =
  375. (uint_t) ((css_new->css_swapin - css_old->css_swapin) *
  376.   getpagesize() / 1024 / time_diff);
  377. /*
  378.  * LINTED cast needed, really 
  379.  */
  380. swapout =
  381. (uint_t) ((css_new->css_swapout - css_old->css_swapout) *
  382.   getpagesize() / 1024 / time_diff);
  383. /*
  384.  * LINTED cast needed, really 
  385.  */
  386. blocks_read =
  387. (uint_t) ((css_new->css_blocks_read - css_old->css_blocks_read) /
  388.   time_diff);
  389. /*
  390.  * LINTED cast needed, really 
  391.  */
  392. blocks_write =
  393. (uint_t) ((css_new->css_blocks_write - css_old->css_blocks_write) /
  394.   time_diff);
  395. /*
  396.  * LINTED cast needed, really 
  397.  */
  398. interrupts =
  399. (uint_t) ((css_new->css_interrupts - css_old->css_interrupts) /
  400.   time_diff);
  401. /*
  402.  * LINTED cast needed, really 
  403.  */
  404. context_sw =
  405. (uint_t) ((css_new->css_context_sw - css_old->css_context_sw) /
  406.   time_diff);
  407. /*
  408.  * Loop thru all the CPU_STATES and get the differences 
  409.  */
  410. for (i = 0; i < CPU_STATES; i++) {
  411. cpu_sum += (css_new->css_cpu[i] - css_old->css_cpu[i]);
  412. }
  413. /*
  414.  * Now calculate the absolute percentage values 
  415.  * Looks somewhat complicated sometimes but tries to get around using floats to increase speed 
  416.  */
  417. for (i = 0; i < CPU_STATES; i++) {
  418. /*
  419.  * Since we don't return fractions we use + 0.5 to get between 99 and 101 percent adding the values 
  420.  * together, otherwise we would get less than 100 most of the time 
  421.  */
  422. /*
  423.  * LINTED has to be 'long' 
  424.  */
  425. cpu_perc[i] =
  426. (long) (((css_new->css_cpu[i] - css_old->css_cpu[i]) * 100 +
  427.  (cpu_sum / 2)) / cpu_sum);
  428. }
  429. /* "system" is "kernel", we have to add "wait" to get the correct value */
  430. cpu_perc[CPU_SYSTEM] += cpu_perc[CPU_WAIT];
  431. }
  432. /*
  433.  * Make the current one the first one and move the whole thing one place down 
  434.  */
  435. memmove(&snapshot[1], &snapshot[0],
  436. (size_t) (((char *) &snapshot[POLL_VALUES]) -
  437.   ((char *) &snapshot[0])));
  438. /*
  439.  * Erase the current one 
  440.  */
  441. memset(&snapshot[0], 0, sizeof snapshot[0]);
  442. /*
  443.  * Only important on start up, we keep track of how many snapshots we have taken so far 
  444.  */
  445. if (number_of_snapshots < POLL_VALUES) {
  446. number_of_snapshots++;
  447. }
  448. }    /* update_stats ends here */
  449. /*
  450.  * *var_extensible_vmstat starts here 
  451.  * The guts of the module, this routine gets called to service a request 
  452.  */
  453. unsigned char *
  454. var_extensible_vmstat(struct variable *vp,
  455.   oid * name,
  456.   size_t * length,
  457.   int exact,
  458.   size_t * var_len, WriteMethod ** write_method)
  459. {
  460. /*
  461.  * Needed for returning the values 
  462.  */
  463. static long  long_ret;
  464. static char  errmsg[300];
  465. /*
  466.  * set to 0 as default 
  467.  */
  468. long_ret = 0;
  469. /*
  470.  * generic check whether the options passed make sense and whether the 
  471.  */
  472. /*
  473.  * right variable is requested 
  474.  */
  475. if (header_generic(vp, name, length, exact, var_len, write_method) !=
  476. MATCH_SUCCEEDED) {
  477. return (NULL);
  478. }
  479. /*
  480.  * The function that actually returns s.th. 
  481.  */
  482. switch (vp->magic) {
  483. case MIBINDEX:
  484. long_ret = 1;
  485. return ((u_char *) (&long_ret));
  486. case ERRORNAME: /* dummy name */
  487. sprintf(errmsg, "systemStats");
  488. *var_len = strlen(errmsg);
  489. return ((u_char *) (errmsg));
  490. case SWAPIN:
  491. return ((u_char *) (&swapin));
  492. case SWAPOUT:
  493. return ((u_char *) (&swapout));
  494. case IOSENT:
  495. return ((u_char *) (&blocks_write));
  496. case IORECEIVE:
  497. return ((u_char *) (&blocks_read));
  498. case SYSINTERRUPTS:
  499. return ((u_char *) (&interrupts));
  500. case SYSCONTEXT:
  501. return ((u_char *) (&context_sw));
  502. case CPUUSER:
  503. return ((u_char *) (&cpu_perc[CPU_USER]));
  504. case CPUSYSTEM:
  505. return ((u_char *) (&cpu_perc[CPU_SYSTEM]));
  506. case CPUIDLE:
  507. return ((u_char *) (&cpu_perc[CPU_IDLE]));
  508. case CPURAWUSER:
  509. take_snapshot(&raw_values);
  510. /*
  511.  * LINTED has to be 'long' 
  512.  */
  513. long_ret =
  514. (long) (raw_values.css_cpu[CPU_USER] / raw_values.css_cpus);
  515. return ((u_char *) (&long_ret));
  516. /*
  517.  * We are missing CPURAWNICE, AIX does not account for this in the kernel so this OID can not 
  518.  * be returned.  Also, these values will roll over sooner or later and then return inaccurate data 
  519.  * but the MIB wants Integer32 so we cannot put a counter here 
  520.  * (Has been changed to Counter32 in the latest MIB version!) 
  521.  */
  522. case CPURAWSYSTEM:
  523. take_snapshot(&raw_values);
  524. /*
  525.  * LINTED has to be 'long' 
  526.  */
  527. long_ret =
  528. (long) ((raw_values.css_cpu[CPU_SYSTEM] +
  529.  raw_values.css_cpu[CPU_WAIT]) / raw_values.css_cpus);
  530. return ((u_char *) (&long_ret));
  531. case CPURAWIDLE:
  532. take_snapshot(&raw_values);
  533. /*
  534.  * LINTED has to be 'long' 
  535.  */
  536. long_ret =
  537. (long) (raw_values.css_cpu[CPU_IDLE] / raw_values.css_cpus);
  538. return ((u_char *) (&long_ret));
  539. case CPURAWWAIT:
  540. take_snapshot(&raw_values);
  541. /*
  542.  * LINTED has to be 'long' 
  543.  */
  544. long_ret =
  545. (long) (raw_values.css_cpu[CPU_WAIT] / raw_values.css_cpus);
  546. return ((u_char *) (&long_ret));
  547. case CPURAWKERNEL:
  548. take_snapshot(&raw_values);
  549. /*
  550.  * LINTED has to be 'long' 
  551.  */
  552. long_ret =
  553. (long) (raw_values.css_cpu[CPU_SYSTEM] / raw_values.css_cpus);
  554. return ((u_char *) (&long_ret));
  555. case IORAWSENT:
  556. long_ret = (long) (raw_values.css_blocks_write);
  557. return ((u_char *) (&long_ret));
  558. case IORAWRECEIVE:
  559. long_ret = (long) (raw_values.css_blocks_read);
  560. return ((u_char *) (&long_ret));
  561. case SYSRAWINTERRUPTS:
  562. long_ret = (long) (raw_values.css_interrupts);
  563. return ((u_char *) (&long_ret));
  564. case SYSRAWCONTEXT:
  565. long_ret = (long) (raw_values.css_context_sw);
  566. return ((u_char *) (&long_ret));
  567. /*
  568.  * reserved for future use 
  569.  */
  570. /*
  571.  * case ERRORFLAG:
  572.  * return((u_char *) (&long_ret));
  573.  * case ERRORMSG:
  574.  * return((u_char *) (&long_ret));
  575.  */
  576. default:
  577. snmp_log(LOG_ERR,
  578.  "vmstat_aix4: Error in request, no match found.n");
  579. }
  580. return (NULL);
  581. }    /* *var_extensible_vmstat ends here */
  582. /*
  583.  * Functions end here 
  584.  */
  585. /*
  586.  * Program ends here 
  587.  */