PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/SysUsage-Sar-2.10/Sar.pm

#
Perl | 401 lines | 212 code | 25 blank | 164 comment | 46 complexity | 01a6b79f6ef3e51d32ed5020a2ede979 MD5 | raw file
  1. package SysUsage::Sar;
  2. #------------------------------------------------------------------------------
  3. # sysusage - Full system monitoring with RRDTOOL
  4. # Copyright (C) 2003-2009 Gilles Darold
  5. #
  6. # This program is provided WITHOUT WARRANTY of any kind, either
  7. # expressed or implied. It is free software, and you are welcome
  8. # to modify or re-distribute it under same terms of Perl itself.
  9. #
  10. # Author: Gilles Darold <gilles@darold.net>
  11. #
  12. # This module grab system information retrieve from sar command
  13. # and provide all method to get these informations.
  14. #------------------------------------------------------------------------------
  15. use strict qw(vars);
  16. BEGIN {
  17. use Exporter();
  18. use vars qw($VERSION $COPYRIGHT $AUTHOR @ISA @EXPORT);
  19. $VERSION = '2.10';
  20. $COPYRIGHT = 'Copyright (c) 2003-2009 Gilles Darold - All rights reserved.';
  21. $AUTHOR = "Gilles Darold - gilles\@darold.net";
  22. @ISA = qw(Exporter);
  23. @EXPORT = qw//;
  24. $| = 1;
  25. }
  26. sub new
  27. {
  28. my ($class, %options) = @_;
  29. my $self = {
  30. 'header' => '',
  31. 'report' => (),
  32. 'data' => (),
  33. 'debug' => 0,
  34. 'sar_cmd' => ''
  35. };
  36. bless $self, $class;
  37. $self->init(%options);
  38. return ($self);
  39. }
  40. sub init
  41. {
  42. my ($self, %options) = @_;
  43. #### Set the sar command to execute.
  44. my $sar = $options{'sar'} || '/usr/bin/sar';
  45. if (!-x $sar) {
  46. die "ERROR: Can't find sar binary at $sar\n";
  47. }
  48. my $opt = $options{'opt'} || '-p -A 1 5';
  49. $self->{'sar_cmd'} = $sar . ' ' . $opt . ' | grep -v -E "^[0-9]"';
  50. $self->{'debug'} = $options{'debug'} || 0;
  51. }
  52. # Return sar output first line. Usually kernel information
  53. sub getHeader
  54. {
  55. my ($self) = @_;
  56. return $self->{header};
  57. }
  58. # Parse Sar output and return a hash
  59. sub parseSarOutput
  60. {
  61. my ($self) = @_;
  62. #### Execute sar command and get result
  63. unless(open(SAR, "$self->{'sar_cmd'} |")) {
  64. die "ERROR: Can't execute command $self->{'sar_cmd'}\n";
  65. }
  66. while (my $line = <SAR>) {
  67. $line =~ s/ //gs;
  68. chomp($line);
  69. push(@{$self->{data}}, $line);
  70. }
  71. close(SAR);
  72. #### Extract sar head line. Usually kernel information
  73. $self->{header} = shift(@{$self->{data}});
  74. print STDERR "Sar header: $self->{header}\n" if ($self->{'debug'});
  75. my $type = '';
  76. my @headers = ();
  77. my @values = ();
  78. for (my $i = 0; $i <= $#{$self->{data}}; $i++) {
  79. # Empty line, maybe the end of a report
  80. if (!$self->{data}[$i]) {
  81. $type = '';
  82. @headers = ();
  83. @values = ();
  84. next;
  85. }
  86. # Remove average header
  87. $self->{data}[$i] =~ s#^[a-z]+:[\s\t]+##i;
  88. # Store all header fields
  89. if ($#headers == -1) {
  90. push(@headers, split(m#\s+#, $self->{data}[$i]));
  91. }
  92. # Try to find the kind of report
  93. if ($self->{data}[$i] =~ m#^proc/s#i) {
  94. $type = 'pcrea';
  95. next;
  96. }
  97. if ($self->{data}[$i] =~ m#^cswch/s#i) {
  98. $type = 'cswch';
  99. next;
  100. }
  101. if ($self->{data}[$i] =~ m#^CPU\s+i\d+#i) {
  102. $type = 'ncpu';
  103. $headers[0] = 'number';
  104. next;
  105. } elsif ($self->{data}[$i] =~ m#^CPU\s+#i) {
  106. $type = 'cpu';
  107. $headers[0] = 'number';
  108. next;
  109. }
  110. if ($self->{data}[$i] =~ m#^INTR\s+#i) {
  111. $type = 'intr';
  112. $headers[0] = 'name';
  113. next;
  114. }
  115. if ($self->{data}[$i] =~ m#^pgpgin/s\s+#i) {
  116. $type = 'page';
  117. next;
  118. }
  119. if ($self->{data}[$i] =~ m#^pswpin/s\s+#i) {
  120. $type = 'pswap';
  121. next;
  122. }
  123. if ($self->{data}[$i] =~ m#^tps\s+#i) {
  124. $type = 'io';
  125. next;
  126. }
  127. if ($self->{data}[$i] =~ m#^frmpg/s\s+#i) {
  128. $type = 'mpage';
  129. next;
  130. }
  131. if ($self->{data}[$i] =~ m#^TTY\s+#i) {
  132. $type = 'tty';
  133. $headers[0] = 'number';
  134. next;
  135. }
  136. if ($self->{data}[$i] =~ m#^IFACE\s+rxpck/s\s+#i) {
  137. $type = 'net';
  138. $headers[0] = 'name';
  139. next;
  140. }
  141. if ($self->{data}[$i] =~ m#^IFACE\s+rxerr/s\s+#i) {
  142. $type = 'err';
  143. $headers[0] = 'name';
  144. next;
  145. }
  146. if ($self->{data}[$i] =~ m#^DEV\s+#i) {
  147. $type = 'dev';
  148. $headers[0] = 'name';
  149. next;
  150. }
  151. if ($self->{data}[$i] =~ m#^kbmemfree\s+#i) {
  152. $type = 'mem';
  153. next;
  154. }
  155. # New in sysstat 8.1.5
  156. if ($self->{data}[$i] =~ m#^kbswpfree\s+#i) {
  157. $type = 'swap';
  158. next;
  159. }
  160. if ($self->{data}[$i] =~ m#^dentunusd\s+#i) {
  161. $type = 'file';
  162. next;
  163. }
  164. if ($self->{data}[$i] =~ m#^totsck\s+#i) {
  165. $type = 'sock';
  166. next;
  167. }
  168. if ($self->{data}[$i] =~ m#^runq-sz\s+#i) {
  169. $type = 'load';
  170. next;
  171. }
  172. # Unknow type of report, skipping
  173. if (!$type) {
  174. @headers = ();
  175. @values = ();
  176. next;
  177. }
  178. # Get all values reported
  179. push(@values, split(m#\s+#, $self->{data}[$i]));
  180. if ($#values != $#headers) {
  181. die "ERROR: Parsing of sar output reports different values than headers allow. ($#values != $#headers)\n";
  182. }
  183. # Store all into the main hash
  184. for (my $j = 0; $j <= $#headers; $j++) {
  185. # Remove extra info into headers
  186. $headers[$j] =~ s#/s##g;
  187. # Change decimal character to perl
  188. $values[$j] =~ s/,/\./;
  189. if ($values[$j] !~ /[a-z]/i) {
  190. # Round decimal up to .50
  191. if ($values[$j] gt 50) {
  192. $values[$j]++;
  193. }
  194. # Store it as integer
  195. $values[$j] = int($values[$j]);
  196. }
  197. # New version of sar report proc and cswch at same time
  198. if ( ($#headers == 1) && ($headers[$j] eq 'cswch') ) {
  199. $self->{report}{'cswch'}{$headers[$j]} = $values[$j];
  200. } elsif ( ($type eq 'mem') && ($headers[$j] eq '%swpused') ) {
  201. $self->{report}{'swap'}{$headers[$j]} = $values[$j];
  202. print STDERR "Sar report 'swap': $headers[$j] => $self->{report}{'swap'}{$headers[$j]}\n" if ($self->{'debug'});
  203. } elsif ( ($type eq 'mem') && ($headers[$j] eq '%commit') ) {
  204. $self->{report}{'work'}{$headers[$j]} = $values[$j];
  205. print STDERR "Sar report 'work': $headers[$j] => $self->{report}{'work'}{$headers[$j]}\n" if ($self->{'debug'});
  206. } elsif ( ($type eq 'mem') && ($headers[$j] eq 'kbcommit') ) {
  207. $self->{report}{'work'}{$headers[$j]} = $values[$j];
  208. print STDERR "Sar report 'work': $headers[$j] => $self->{report}{'work'}{$headers[$j]}\n" if ($self->{'debug'});
  209. } elsif (!grep(/^$headers[0]$/, 'name', 'number')) {
  210. $self->{report}{$type}{$headers[$j]} = $values[$j];
  211. print STDERR "Sar report '$type': $headers[$j] => $self->{report}{$type}{$headers[$j]}\n" if ($self->{'debug'});
  212. } else {
  213. next if ( ($type eq 'intr') && ($values[0] ne 'sum') );
  214. $headers[$j] = '%user' if ( ($type eq 'cpu') && ($headers[$j] eq '%usr'));
  215. $headers[$j] = '%system' if ( ($type eq 'cpu') && ($headers[$j] eq '%sys'));
  216. $self->{report}{$type}{$values[0]}{$headers[$j]} = $values[$j];
  217. print STDERR "Sar report '$type' ($values[0]): $headers[$j] => $self->{report}{$type}{$values[0]}{$headers[$j]}\n" if ($self->{'debug'});
  218. }
  219. }
  220. @values = ();
  221. }
  222. }
  223. # Return a hash of the given type of report. Here are the allowed type
  224. # of report and the corresponding fields:
  225. #
  226. # 'pcrea' Report process creation activity
  227. #
  228. # proc => Total number of processes created per second
  229. #
  230. # 'cswch' Report system switching activity
  231. #
  232. # cswch => Total number of context switches per second
  233. #
  234. # 'cpu' Report CPU utilization.
  235. #
  236. # %user => Percentage of CPU utilization at the user level (application)
  237. # %nice => Percentage of CPU utilization at the user level with nice priority
  238. # %system => Percentage of CPU utilization at system level (kernel, I/O)
  239. # %iowait => percentage of CPU time spent waiting on disk I/O
  240. # %steal => percentage of time spent in involuntary wait by the virtual CPU or CPUs while the hypervisor was servicing another virtual processor
  241. # %idle => Percentage of time that the CPU were idle
  242. #
  243. # 'intr' Report interrupt statistics
  244. #
  245. # name => Identifier (can be sum or a number ???)
  246. # intr => Interrupts per second
  247. #
  248. # 'page' Report paging statistics
  249. #
  250. # pgpgin => Total number of blocks the system paged in from disk per second
  251. # pgpgout => Total number of blocks the system paged out to disk per second
  252. # fault => Number of page faults (major + minor) made by the system per second
  253. # majflt => Number of major faults the system has made per second
  254. #
  255. # 'pswap' Report swapping statistics
  256. #
  257. # pswpin => Total number of swap pages the system brought in per second
  258. # pswpout => Total number of swap pages the system brought out per second
  259. #
  260. # 'io' Report I/O and transfer rate statistics
  261. #
  262. # tps => Total transfers per second that were issued to the physical disk
  263. # rtps => Total read requests per second issued to the physical disk
  264. # wtps => Total write requests per second issued to the physical disk
  265. # bread => Total amount of data read from the drive in blocks per second
  266. # bwrtn => Total amount of data written to the drive in blocks per second
  267. #
  268. # 'mpage' Report memory statistics
  269. #
  270. # frmpg => Number of memory pages freed by the system per second
  271. # shmpg => Number of additionnal memory pages shared by the system per second
  272. # bufpg => Number of additionnal memory pages used as buffers by the system per second
  273. # campg => Number of additionnal memory pages cached by the system per second
  274. #
  275. # 'tty' Report TTY device activity
  276. #
  277. # number => Serial line number
  278. # rcvin => Number of receive interrupts per second
  279. # xmtin => Number of transmit interrupts per second
  280. #
  281. # 'net' Report network statistics
  282. #
  283. # name => Name of the network interface for which statistics are reported
  284. # rxpck => Total number of packets received per second
  285. # txpck => Total number of packets transmitted per second
  286. # rxbyt => Total number of bytes received per second
  287. # txbyt => Total number of bytes transmitted per second
  288. # rxcmp => Number of compressed packets received per second
  289. # txcmp => Number of compressed packets transmitted per second
  290. # rxmcst => Number of multicast packets received per second
  291. #
  292. # 'err' Report network failure statistics
  293. #
  294. # name => Name of the network interface for which statistics are reported
  295. # rxerr => Total number of bad packets received per second
  296. # txerr => Total number of errors that happened per second
  297. # coll => Number of collisions that happened per second
  298. # rxdrop => Number of received packets dropped per second
  299. # txdrop => Number of transmitted packets dropped per second
  300. # txcarr => Number of carrier-errors that happened per second
  301. # rxfram => Number of frame alignment errors that happened per second on received packets
  302. # rxfifo => Number of FIFO overrun errors that happened per second on received packets
  303. # txfifo => Number of FIFO overrun errors that happened per second on transmitted packets
  304. #
  305. # 'dev' Report activity for each block device
  306. #
  307. # name => Name of the device (dev-major-minor or realname with -p)
  308. # tps => Indicate the number of transfers per second that were issued to the device
  309. # rd_sec => Number of sectors read from the device. The size of a sector is 512 bytes
  310. # wr_sec => Number of sectors written to the device. The size of a sector is 512 bytes
  311. #
  312. # 'mem' Report memory and swap space
  313. #
  314. # kbmemfree => Amount of free memory available in kilobytes
  315. # kbmemused => Amount of used memory in kilobytes
  316. # %memused => Percentage of used memory
  317. # kbbuffers => Amount of memory used as buffers by the kernel in kilobytes
  318. # kbcached => Amount of memory used to cache data by the kernel in kilobytes
  319. # kbswpfree => Amount of free swap space in kilobytes
  320. # kbswpused => Amount of used swap space in kilobytes
  321. # %swpused => Percentage of used swap space
  322. # kbswpcad => Amount of cached swap memory in kilobytes
  323. # kbcommit => Amount of memory needed for current workload
  324. # %commit => Percentage of memory needed for current workload
  325. #
  326. # 'file' Report status of inode, file and other kernel tables
  327. #
  328. # dentunusd => Number of unused cache entries in the directory cache
  329. # file-sz => Number of used file handles
  330. # %file-sz => Percentage of used file handles with regard to the maximum number of file handles
  331. # inode-sz => Number of used inode handlers
  332. # super-sz => Number of super block handlers allocated by the kernel
  333. # %super-sz => Percentage of allocated super block handlers with regard to the
  334. # maximum number of super block handlers that Linux can allocate.
  335. # dquot-sz => Number of allocated disk quota entries.
  336. # %dquot-sz => Percentage of allocated disk quota entries with regard to the
  337. # maximum number of cached disk quota entries that can be allocated.
  338. # rtsig-sz => Number of queued RT signals
  339. # %rtsig-sz => Percentage of queued RT signals with regard to the maximum number
  340. # of RT signals that can be queued.
  341. #
  342. # 'sock' Report sockets in use statistics
  343. #
  344. # totsck => Total number of used sockets
  345. # tcpsck => Number of TCP sockets currently in use
  346. # udpsck => Number of UDP sockets currently in use
  347. # rawsck => Number of RAW sockets currently in use
  348. # ip-frag => Number of IP fragments currently in use
  349. #
  350. # 'load' Report queue length and load averages
  351. #
  352. # runq-sz => Run queue length (number of processes waiting for run time)
  353. # plist-sz => Number of processes in the process list
  354. # ldavg-1 => System load average for the last minute
  355. # ldavg-5 => System load average for the past 5 minutes
  356. # ldavg-15 => System load average for the past 15 minutes
  357. #
  358. #
  359. sub getReportType
  360. {
  361. my ($self, $type) = @_;
  362. die "ERROR: bad report type $type\n" if (!exists $self->{report}{$type});
  363. return %{$self->{report}{$type}};
  364. }
  365. sub getReport
  366. {
  367. my ($self, $type) = @_;
  368. return %{$self->{report}};
  369. }
  370. 1;
  371. __END__