runit.pl 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/perl -w
  2. #
  3. # Author: Jue Ruan <ruanjue@gmail.com>
  4. #
  5. use strict;
  6. use warnings;
  7. use POSIX;
  8. use POSIX ":sys_wait_h";
  9. use Time::HiRes;
  10. my $USER = $ENV{USER};
  11. if(not defined $USER){
  12. $USER = `whoami`;
  13. chomp $USER;
  14. }
  15. my $RUNITALL = $ENV{RUNIT_ALL} || 0;
  16. my $cmd = join(" ", @ARGV);
  17. $cmd=~s/^\s+//;
  18. $cmd=~s/\s+$//;
  19. &usage unless($cmd);
  20. my $pagesize = POSIX::sysconf(POSIX::_SC_PAGESIZE);
  21. my $sleep_inv = 1000000; # in mircoseconds
  22. my $maxram = 0; # kb
  23. my $maxcpu = 0;
  24. my $retval = 0;
  25. my $utime = 0;
  26. my $stime = 0;
  27. my $rtime = 0;
  28. my $maxrss = 0;
  29. my $maxvsz = 0;
  30. my %exclusive = ();
  31. if($RUNITALL){
  32. for my $proc (&get_all_process()){
  33. $exclusive{$proc->[0]} = 1;
  34. }
  35. }
  36. my %procs = ();
  37. &get_linux_sys_info();
  38. print STDERR " --------------------------------------------------------------------------------\n";
  39. print STDERR " -- runit.pl is a program launcher and minitor written by Jue Ruan <ruanjue\@gmail.com>\n";
  40. print STDERR " -- RAM : $maxram kB\n";
  41. print STDERR " -- CPU : $maxcpu cores\n";
  42. print STDERR " -- SYS : ", `uname -a`;
  43. print STDERR " -- USER: $USER\n";
  44. print STDERR " -- DATE: ", `date`;
  45. print STDERR " -- PWD : ", `pwd`;
  46. print STDERR " -- CMD : $cmd\n";
  47. print STDERR " --------------------------------------------------------------------------------\n";
  48. my $PID = open(READ, "$cmd |") or die("Cannot invoke commands: $!");
  49. my $begtime = Time::HiRes::time;
  50. if(fork() == 0){
  51. while(<READ>){
  52. print;
  53. }
  54. exit;
  55. }
  56. while(1){
  57. my $mrss = 0;
  58. my $mvsz = 0;
  59. foreach my $proc (&get_all_process()){
  60. my ($pid, $cm, $ppid) = @{$proc};
  61. next if($exclusive{$pid});
  62. my ($fail, $ut, $st, $rss, $vsz) = &get_linux_proc_info($pid);
  63. next if($fail);
  64. if(exists $procs{$pid}){
  65. $procs{$pid}[0] = $ut;
  66. $procs{$pid}[1] = $st;
  67. } else {
  68. print STDERR " -- RUNIT PID($pid): $ppid\t$cm\n";
  69. $procs{$pid} = [$ut, $st, $cm, $ppid];
  70. }
  71. $mrss += $rss;
  72. $mvsz += $vsz;
  73. }
  74. #print STDERR "$mrss\t$mvsz\n";
  75. $maxrss = $mrss if($mrss > $maxrss);
  76. $maxvsz = $mvsz if($mvsz > $maxvsz);
  77. my $res = waitpid($PID, WNOHANG);
  78. if($res == -1){
  79. print STDERR " ** Error ", ($? >> 8), "\n";
  80. last;
  81. } elsif($res){
  82. $retval = $? >> 8;
  83. last;
  84. } else {
  85. Time::HiRes::usleep($sleep_inv);
  86. }
  87. }
  88. my $endtime = Time::HiRes::time;
  89. $rtime = $endtime - $begtime;
  90. foreach my $pid (sort {$a <=> $b} keys %procs){
  91. next if($exclusive{$pid});
  92. print STDERR " -- STAT PID($pid): $procs{$pid}[3]\t$procs{$pid}[0]\t$procs{$pid}[1]\t$procs{$pid}[2]\n";
  93. $utime += $procs{$pid}[0];
  94. $stime += $procs{$pid}[1];
  95. }
  96. print STDERR " --------------------------------------------------------------------------------\n";
  97. printf STDERR " -- retval %16d\n", $retval;
  98. printf STDERR " -- real %16.3f\n", $rtime;
  99. printf STDERR " -- user %16.3f\n", $utime;
  100. printf STDERR " -- sys %16.3f\n", $stime;
  101. printf STDERR " -- maxrss %16.3f kB\n", $maxrss;
  102. printf STDERR " -- maxvsz %16.3f kB\n", $maxvsz;
  103. print STDERR " --------------------------------------------------------------------------------\n";
  104. 1;
  105. sub usage {
  106. print qq{Launch program and minitor the cputime and ram usage of it and its childs\n};
  107. print qq{Usage: $0 \$'commands'\n};
  108. exit 1;
  109. }
  110. sub get_linux_sys_info {
  111. open(IN, "/proc/meminfo") or die;
  112. while(<IN>){
  113. my @ts = split;
  114. if($ts[0]=~/^MemTotal/){
  115. $maxram = $ts[1];
  116. last;
  117. }
  118. }
  119. close IN;
  120. open(IN, "/proc/cpuinfo") or die;
  121. $maxcpu = 0;
  122. while(<IN>){
  123. if(/^processor/){
  124. $maxcpu ++;
  125. }
  126. }
  127. close IN;
  128. }
  129. sub get_all_process {
  130. my %ps = ();
  131. my @pids = ();
  132. if(my $psid = open(IN, "ps -o ppid,pid,cmd --no-headers --user $USER 2>/dev/null |")){
  133. while(<IN>){
  134. chomp;
  135. my @ts = split /\s+/, $_, 3;
  136. next if($ts[1] == $psid);
  137. if($RUNITALL){
  138. push(@pids, [$ts[1], $ts[2], $ts[0]]);
  139. } else {
  140. $ps{$ts[1]}[0] = $ts[2];
  141. $ps{$ts[1]}[1] = $ts[0];
  142. $ps{$ts[1]}[2] = [] if(not defined $ps{$ts[1]}[2]);
  143. push(@{$ps{$ts[0]}[2]}, $ts[1]);
  144. }
  145. }
  146. close IN;
  147. }
  148. if($RUNITALL){
  149. } else {
  150. my @stack = ($PID);
  151. while(@stack){
  152. my $pid = pop @stack;
  153. next unless(exists $ps{$pid});
  154. my $p = $ps{$pid};
  155. push(@pids, [$pid, $p->[0], $p->[1]]);
  156. push(@stack, @{$p->[2]});
  157. }
  158. }
  159. return @pids;
  160. }
  161. sub get_linux_proc_info {
  162. my $pid = shift;
  163. my ($fail, $ut, $st, $rss, $vsz);
  164. if(open(IN, "/proc/$pid/stat")){
  165. if($_ = <IN>){
  166. my @ts = split /\s/, $_;
  167. #print STDERR join("|", @ts), "\n";
  168. #for(my $i=0;$i<@ts;$i++){
  169. # print STDERR ($i+1), "\t", $ts[$i], "\n";
  170. #}
  171. $ut = $ts[13] / 100;
  172. $st = $ts[14] / 100;
  173. $vsz = $ts[22] / 1024;
  174. $rss = $ts[23] * $pagesize / 1024;
  175. $fail = 0;
  176. } else {
  177. $fail = 1;
  178. }
  179. close IN;
  180. } else {
  181. $fail = 1;
  182. }
  183. if($fail){
  184. print STDERR " ** FAIL STAT($pid)\n";
  185. }
  186. return ($fail, $ut, $st, $rss, $vsz);
  187. }