#!/usr/bin/perl $swaplimit=shift; if($swaplimit==0) { $swaplimit=200000; } $older_limit=60000; $fast=5; $fast=0; $slow=90; $extraslow=180; $maxextraslow=1200; $pausecont=$extraslow; if($fast) { $pause=$fast; } else { $pause=$slow; } $notstop_regex="|^xz"; $iomin=0.02; $iomax=0.20; $MINIDLE=0.65; $MAXIDLE=0.80; $continue=$pause; $lastwait=-1; $lastsum=-1; $iowait=0; sub sigquit { my ($sig)=@_; print STDERR "Caught a SIG$sig. Save stopped pids and quit.\n"; unlink("pids.stop.backup"); rename("pids.stop","pids.stop.backup"); open(D,">pids.stop"); foreach $k (keys %stop) { if($stop{$k}>0) { print D "$k=$stop{$k}\n"; } } close(D); exit(0); } $SIG{TERM}=\&sigquit; $SIG{QUIT}=\&sigquit; $SIG{INT}=\&sigquit; $SIG{HUP}=\&sigquit; $SIG{TSTP}=\&sigquit; sub loadpids { if(open(D,"pids.stop")) { while($l=) { ($pid,$time)=split("=",$l); $time+=0; $stop{$pid}=$time; } close(D); } } sub sortpid { ($resa,undef,$pida)=split(" ",$a); ($resb,undef,$pidb)=split(" ",$b); if($resa>$older_limit || $resb>$older_limit) { # Normal sort } elsif($stop{$pida}>0 && $stop{$pidb}>0) { return($stop{$pida} <=> $stop{$pidb}); } return($resb <=> $resa); } sub getcc1plus { # cpu open(CPU,"/proc/stat"); (undef,$cpu_user,$cpu_nice,$cpu_sytem,$cpu_idle,$cpu_iowait)=split(' ',); close(CPU); $sum=$cpu_user+$cpu_nice+$cpu_sytem+$cpu_idle+$cpu_iowait; if($lastsum<0) { $lastsum=$sum; $lastwait=$cpu_iowait; $lastidle=$cpu_idle; } elsif(($sum-$lastsum)>15000) { $iowait=($cpu_iowait-$lastwait)/($sum-$lastsum); $idle=($cpu_idle-$lastidle)/($sum-$lastsum); $lastsum=$sum; $lastwait=$cpu_iowait; $lastidle=$cpu_idle; } # USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND # root 12722 0.8 3.8 56452 9644 pts/1 T+ 14:07 0:04 /usr/libexec/gcc/armv7hl-slackware-linux-gnueabi/5.3.0/cc1plus -quiet -I # root@opzero:~# ps -eo pid,ppid,stat,pcpu,vsz,rss,size,time,comm | head -2 # PID PPID STAT %CPU VSZ RSS SIZE TIME COMMAND # 1 0 Ss 0.2 1848 1296 296 00:00:05 init #my @ps=grep(genautomata|genattrtab|/cc1|smokegen|\/as|\/ld/,split("\n",`ps aux`)); my @ps=grep(/ xz| cc1| gnat1| go1| ecj| ecj1| jc1| java| gij| rust| clang| f951| lto1| d21| makeinfo| genautomata| genattrtab| smokegen| ld|tblgen/,split("\n",`ps -eo pid,ppid,stat,pcpu,vsz,rss,size,time,comm`)); my @ret=(); $running=0; $stopped=0; $genautomata=0; $maxres=-1; $maxall=-1; $resdiff=-1; $candidaterun=-1; $candidateall=-1; $swapstop=0; $totres=0; %active=(); foreach(@ps) { ($pid,$ppid,$stat,$cpu,$vsz,$res,$size,$time,@cmd)=split; $cmd=join(" ",@cmd); ($hour,$min,$sec)=split(":",$time); $time=$hour*3600+$min*60+$sec; if($cmd=~m/genautomata/) { $genautomata=$pid; } if($stat=~m/^Z/) { # Zombie/defunct, do not count next; } elsif($stat=~m/^T/) { if($stop{$pid}==0) { $stop{$pid}=time(); } $stopped++; $curres=$vsz-$res; if($maxres<0 || $res>$maxres) { if($resdiff>0) { $swapstop+=$resdiff; } $maxres=$res; $resdiff=$curres; $candidaterun=$pid; $candidatevsz=$vsz; } else { $swapstop+=$curres; } } else { $running++; $totres+=$res; } if($maxall<0 || $res>$maxall) { $maxall=$res; $candidateall=$pid; } $active{$pid}=1; push(@ret,"$res * $pid $stat ($vsz $time) $cmd"); } foreach(keys %stop) { if(!$active{$_}) { delete($stop{$_}); } } @ret=sort sortpid @ret; if(0) { foreach(@ret) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$_); if($stop{$pid}>0) { $stp=time()-$stop{$pid}; $stp="(stop since $stp)"; } else { $stp=""; } print "SP: $_ $stp\n"; } } if($maxall<=$older_limit) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$ret[0]); $candidateall=$pid; } return(@ret); } loadpids(); @ps=getcc1plus(); for($i=0;$i<=$#ps;$i++) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$ps[$i]); if($stop{$pid}>0) { $stp=time()-$stop{$pid}; $stp="(stop since $stp)"; } else { $stp=""; } print $ps[$i]," $stp\n"; } $firstprint=1; $t0cont=time(); while(1) { open(F,"/proc/meminfo"); $total=0; $avail=0; #MemTotal: 248572 kB #MemAvailable: 104560 kB while() { if(m/MemAvailable/) { (undef,$avail)=split; } elsif(m/MemTotal/) { (undef,$total)=split; } } close(F); $maxswap=$total/2; if($maxswap>$swaplimit) { $maxswap=$swaplimit; } $swapuse=0; #Filename Type Size Used Priority #/dev/mmcblk0p3 partition 1678788 205568 -1 open(F,"/proc/swaps"); ; while() { (undef,undef,undef,$used)=split; $swapuse+=$used; } close(F); if($continue>0) { @ps=getcc1plus(); $continue--; } elsif($recheck<=0) { @ps=getcc1plus(); $recheck=30; } $recheck--; $swapnostop=$swapuse-$swapstop; if($firstprint) { print scalar(localtime)," - FTOT=$total, AVAIL=$avail, SWAP=$swapuse ($swapnostop) IO=".sprintf("%.1f",$iowait*100).", ID=".sprintf("%.1f",$idle*100)." (run=$running, stop=$stopped) MAXRES=$maxres ($resdiff), CANDIDATE=$candidaterun\n"; $firstprint=0; } if($avail>($total/4)) { $juststopped--; } elsif($avail<($total/8) && ($juststopped>0 || $stopped>0) && $juststopped<$slow) { $juststopped=$slow; } if($running==1 && $stopped>0 && $avail<($total/16) && ($idle<$MAXIDLE)) { $continue=$pausecont; $norun2=$extraslow; } if($running>0 && (($totres)/$running)>($avail-($total/8)) && ($idle<$MAXIDLE)) { $continue=$pausecont; } if($norun2>0) { $norun2--; } $dbg++; if($dbg>=10 && ($continue>0 || $norun2>0 || $juststopped>0)) { print scalar(localtime)," - AVAIL=$avail, TOTRES=$totres, ID=".sprintf("%.1f",$idle*100)." (run=$running, stop=$stopped, cont=$continue, nor2=$norun2, js=$juststopped)\n"; $dbg=0; } if( $running>1 && ($idle<$MINIDLE || $iowait>$iomax) && ( ($norun2>0) || ( $stopped<($running-1) && ($swapuse>($avail)) && ($avail<($total/2)) ) || ($genautomata) || ($avail<($total/8)) || ($avail<($total/4) && $juststopped>0 ) ) ) { print scalar(localtime)," - STOT=$total, AVAIL=$avail, SWAP=$swapuse, ID=".sprintf("%.1f",$idle*100)." (run=$running, stop=$stopped), ID=".sprintf("%.1f",$idle*100)."\n"; @ps=getcc1plus(); if($avail<($total/8)) { $juststopped=$pausecont; } else { $juststopped+=20; } $firstprint=1; $first=0; if($norun2<=10) { $continue+=10; } elsif($continue<$pause) { $continue=$pause; } $t0cont=time(); for($i=0;$i<=$#ps;$i++) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$ps[$i]); if($stop{$pid}>0) { $stp=time()-$stop{$pid}; $stp="(stop since $stp)"; } else { $stp=""; } if(!($stat=~m/^T/)) { if(($genautomata && $genautomata!=$pid) || (!$genautomata && $first>0)) { system("kill -STOP $pid"); if($stop{$pid}==0) { $stop{$pid}=time(); } print "## Stopping $ps[$i]... $stp\n"; } else { print "## Leave continuing $ps[$i]... $stp\n"; } $first++; } else { print "## Already stopped $ps[$i]. $stp\n"; } } if($first>0) { #sleep(20); } @ps=getcc1plus(); } elsif($continue==0 && $norun2<=0 && $stopped && (!$genautomata || $running==0) && ( ($swapuse<($avail) && ($avail>($total/4) || ($avail>($total/8) && $juststopped<=0) ) ) || ($avail>($total/2)) || ($running==0) )) { # Check if the new process will fit in memory after full run #if($running==0 || (($total-$avail)/$running)<($avail-$total/8)) if($running==0 || (($totres)/$running)<($avail-$total/8)) { print scalar(localtime)," - CTOT=$total, AVAIL=$avail, SWAP=$swapuse, ID=".sprintf("%.1f",$idle*100)." (run=$running, stop=$stopped)\n"; @ps=getcc1plus(); $firstprint=1; for($i=0;$i<=$#ps;$i++) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$ps[$i]); if($stop{$pid}>0) { $stp=time()-$stop{$pid}; $stp="(stop since $stp)"; } else { $stp=""; } if($stat=~m/^T/ && (!$genautomata || $genautomata==$pid)) { system("kill -CONT $pid"); #delete($stop{$pid}); $t0cont=time(); print "## Continuing $ps[$i]... $stp\n"; $continue=$pausecont; @ps=getcc1plus(); last; } } } } elsif($continue==0 && $norun2<=0 && $stopped>0 && (!$genautomata || $running==0) && $candidaterun>0 && ($resdiff*1.5)<$avail && $candidatevsz<$avail && $avail>($total/8) && $swapnostop<$avail && ($avail>($total/4) || $juststopped<=0)) { if(0) { # First of all, stop running processes for($i=0;$i<=$#ps;$i++) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$ps[$i]); if(!($stat=~m/^T/)) { system("kill -STOP $pid"); print "## Stopping $ps[$i] to allow more res running...\n"; } } } # The run the candidate for($i=0;$i<=$#ps;$i++) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$ps[$i]); if($stop{$pid}>0) { $stp=time()-$stop{$pid}; $stp="(stop since $stp)"; } else { $stp=""; } if($pid==$candidaterun) { system("kill -CONT $pid"); #delete($stop{$pid}); $t0cont=time(); print "## Fit in memory, continuing $ps[$i]... $stp\n"; break; } } $continue=$pausecont; sleep(1); @ps=getcc1plus(); } elsif($stopped>0) { if($running==0) { if($pauserun<=0) { $running=1; } else { $pauserun--; } } if($running==1) { # First of all, stop running processes for($i=0;$i<=$#ps;$i++) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$ps[$i]); if(!($stat=~m/^T/) && $pid!=$candidateall) { system("kill -STOP $pid"); if($stop{$pid}==0) { $stop{$pid}=time(); } print "## ".scalar(localtime)." - Stopping $ps[$i] to allow best candidate to run...\n"; } } # Recalculate best-candidate: @ps=getcc1plus(); # The run the candidate for($i=0;$i<=$#ps;$i++) { ($res,undef,$pid,$stat,$vsz,$time)=split(" ",$ps[$i]); if($stop{$pid}>0) { $stp=time()-$stop{$pid}; $stp="(stop since $stp)"; } else { $stp=""; } if(($stat=~m/^T/) && $pid==$candidateall) { system("kill -CONT $pid"); #delete($stop{$pid}); print "## ".scalar(localtime)." - Continuing the best candidate $ps[$i] ($continue)... $stp\n"; if($norun2<=0 && $continue<=10) { $continue+=10; } $norun2+=10; break; } } #$continue=$pause; $pauserun=5; } } if((time()-$t0cont)>($pausecont+10)) { $t0cont=time(); if($continue<=0 || ($idle>$MAXIDLE && $iowait<$iomax)) { if($pausecont>$extraslow) { $pausecont-=20; } } else { if($pausecont<$maxextraslow && $running<=$stopped) { $pausecont+=20; } } } sleep(1); }