sm_proc.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright (c) 2001-2012 Willem Dijkstra
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * - Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * - Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following
  13. * disclaimer in the documentation and/or other materials provided
  14. * with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  19. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  20. * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  22. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  26. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. * POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. */
  30. /*
  31. * Get process statistics from kernel and return them in symon_buf as
  32. *
  33. * number of processes : ticks_user : ticks_system : ticks_interrupt :
  34. * cpuseconds : procsizes : resident segment sizes
  35. *
  36. */
  37. #include "conf.h"
  38. #include <sys/param.h>
  39. #include <sys/sysctl.h>
  40. #include <limits.h>
  41. #include <string.h>
  42. #include <unistd.h>
  43. #include "error.h"
  44. #include "symon.h"
  45. #include "xmalloc.h"
  46. #define pagetob(size) (((u_int32_t)size) << proc_pageshift)
  47. #ifdef HAS_KERN_PROC2
  48. #define KINFO_NEWAPI
  49. #define KINFO_MIB KERN_PROC2
  50. #define KINFO_STRUCT kinfo_proc2
  51. #else
  52. #ifndef HAS_KERN_KPPROC
  53. #define KINFO_NEWAPI
  54. #define KINFO_MIB KERN_PROC
  55. #define KINFO_STRUCT kinfo_proc
  56. #else
  57. #undef KINFO_NEWAPI
  58. #define KINFO_STRUCT kinfo_proc
  59. #endif
  60. #endif
  61. /* Globals for this module start with proc_ */
  62. static struct KINFO_STRUCT *proc_ps = NULL;
  63. static int proc_max = 0;
  64. static int proc_cur = 0;
  65. static int proc_stathz = 0;
  66. static int proc_pageshift;
  67. static int proc_pagesize;
  68. /* get scale factor cpu percentage counter */
  69. #define FIXED_PCTCPU FSCALE
  70. typedef long pctcpu;
  71. #define pctdouble(p) ((double)(p) / FIXED_PCTCPU)
  72. void
  73. gets_proc()
  74. {
  75. int mib[6];
  76. int procs;
  77. size_t size;
  78. /* how much memory is needed */
  79. mib[0] = CTL_KERN;
  80. mib[1] = KERN_NPROCS;
  81. size = sizeof(procs);
  82. if (sysctl(mib, 2, &procs, &size, NULL, 0) < 0) {
  83. fatal("%s:%d: sysctl failed: can't get kern.nproc",
  84. __FILE__, __LINE__);
  85. }
  86. #ifdef KINFO_NEWAPI
  87. /* increase buffers if necessary */
  88. if (procs > proc_max) {
  89. proc_max = (procs * 5) / 4;
  90. if (proc_max > SYMON_MAX_DOBJECTS) {
  91. fatal("%s:%d: dynamic object limit (%d) exceeded for kinfo_proc structures",
  92. __FILE__, __LINE__, SYMON_MAX_DOBJECTS);
  93. }
  94. proc_ps = xrealloc(proc_ps, proc_max * sizeof(struct KINFO_STRUCT));
  95. }
  96. /* read data in anger */
  97. mib[0] = CTL_KERN;
  98. mib[1] = KINFO_MIB;
  99. mib[2] = KERN_PROC_KTHREAD;
  100. mib[3] = 0;
  101. mib[4] = sizeof(struct KINFO_STRUCT);
  102. mib[5] = proc_max;
  103. size = proc_max * sizeof(struct KINFO_STRUCT);
  104. if (sysctl(mib, 6, proc_ps, &size, NULL, 0) < 0) {
  105. warning("proc probe cannot get processes");
  106. proc_cur = 0;
  107. return;
  108. }
  109. if (size % sizeof(struct KINFO_STRUCT) != 0) {
  110. warning("proc size mismatch: got %d bytes, not dividable by sizeof(kinfo_proc) %d",
  111. size, sizeof(struct KINFO_STRUCT));
  112. proc_cur = 0;
  113. } else {
  114. proc_cur = size / sizeof(struct KINFO_STRUCT);
  115. }
  116. #else
  117. /* increase buffers if necessary */
  118. if (procs > proc_max) {
  119. proc_max = (procs * 5) / 4;
  120. if (proc_max > SYMON_MAX_DOBJECTS) {
  121. fatal("%s:%d: dynamic object limit (%d) exceeded for kinfo_proc structures",
  122. __FILE__, __LINE__, SYMON_MAX_DOBJECTS);
  123. }
  124. proc_ps = xrealloc(proc_ps, proc_max * sizeof(struct kinfo_proc));
  125. }
  126. /* read data in anger */
  127. mib[0] = CTL_KERN;
  128. mib[1] = KERN_PROC;
  129. mib[2] = KERN_PROC_KTHREAD;
  130. size = proc_max * sizeof(struct kinfo_proc);
  131. if (sysctl(mib, 3, proc_ps, &size, NULL, 0) < 0) {
  132. warning("proc probe cannot get processes");
  133. proc_cur = 0;
  134. return;
  135. }
  136. if (size % sizeof(struct kinfo_proc) != 0) {
  137. warning("proc size mismatch: got %d bytes, not dividable by sizeof(kinfo_proc) %d",
  138. size, sizeof(struct kinfo_proc));
  139. proc_cur = 0;
  140. } else {
  141. proc_cur = size / sizeof(struct kinfo_proc);
  142. }
  143. #endif
  144. }
  145. void
  146. privinit_proc()
  147. {
  148. /* EMPTY */
  149. }
  150. void
  151. init_proc(struct stream *st)
  152. {
  153. int mib[2] = {CTL_KERN, KERN_CLOCKRATE};
  154. struct clockinfo cinf;
  155. size_t size = sizeof(cinf);
  156. /* get clockrate */
  157. if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) {
  158. fatal("%s:%d: could not get clockrate", __FILE__, __LINE__);
  159. }
  160. proc_stathz = cinf.stathz;
  161. /* get pagesize */
  162. proc_pagesize = sysconf(_SC_PAGESIZE);
  163. proc_pageshift = 0;
  164. while (proc_pagesize > 1) {
  165. proc_pageshift++;
  166. proc_pagesize >>= 1;
  167. }
  168. info("started module proc(%.200s)", st->arg);
  169. }
  170. int
  171. get_proc(char *symon_buf, int maxlen, struct stream *st)
  172. {
  173. int i;
  174. struct KINFO_STRUCT *pp;
  175. u_quad_t cpu_ticks = 0;
  176. u_quad_t cpu_uticks = 0;
  177. u_quad_t cpu_iticks = 0;
  178. u_quad_t cpu_sticks =0;
  179. u_int32_t cpu_secs = 0;
  180. double cpu_pct = 0;
  181. double cpu_pcti = 0;
  182. u_int32_t mem_procsize = 0;
  183. u_int32_t mem_rss = 0;
  184. int n = 0;
  185. for (pp = proc_ps, i = 0; i < proc_cur; pp++, i++) {
  186. #ifdef KINFO_NEWAPI
  187. if (strncmp(st->arg, pp->p_comm, strlen(st->arg)) == 0) {
  188. /* cpu time - accumulated */
  189. cpu_uticks += pp->p_uticks; /* user */
  190. cpu_sticks += pp->p_sticks; /* sys */
  191. cpu_iticks += pp->p_iticks; /* int */
  192. /* cpu time - percentage since last measurement */
  193. cpu_pct = pctdouble(pp->p_pctcpu) * 100.0;
  194. cpu_pcti += cpu_pct;
  195. /* memory size - shared pages are counted multiple times */
  196. mem_procsize += pagetob(pp->p_vm_tsize + /* text pages */
  197. pp->p_vm_dsize + /* data */
  198. pp->p_vm_ssize); /* stack */
  199. mem_rss += pagetob(pp->p_vm_rssize); /* rss */
  200. #else
  201. if (strncmp(st->arg, pp->kp_proc.p_comm, strlen(st->arg)) == 0) {
  202. /* cpu time - accumulated */
  203. cpu_uticks += pp->kp_proc.p_uticks; /* user */
  204. cpu_sticks += pp->kp_proc.p_sticks; /* sys */
  205. cpu_iticks += pp->kp_proc.p_iticks; /* int */
  206. /* cpu time - percentage since last measurement */
  207. cpu_pct = pctdouble(pp->kp_proc.p_pctcpu) * 100.0;
  208. cpu_pcti += cpu_pct;
  209. /* memory size - shared pages are counted multiple times */
  210. mem_procsize += pagetob(pp->kp_eproc.e_vm.vm_tsize + /* text pages */
  211. pp->kp_eproc.e_vm.vm_dsize + /* data */
  212. pp->kp_eproc.e_vm.vm_ssize); /* stack */
  213. mem_rss += pagetob(pp->kp_eproc.e_vm.vm_rssize); /* rss */
  214. #endif
  215. n++;
  216. }
  217. }
  218. /* calc total cpu_secs spent */
  219. cpu_ticks = cpu_uticks + cpu_sticks + cpu_iticks;
  220. cpu_secs = cpu_ticks / proc_stathz;
  221. return snpack(symon_buf, maxlen, st->arg, MT_PROC,
  222. n,
  223. cpu_uticks, cpu_sticks, cpu_iticks, cpu_secs, cpu_pcti,
  224. mem_procsize, mem_rss );
  225. }