diff --git a/src/niceload b/src/niceload index 1ee67064..e1546cd3 100755 --- a/src/niceload +++ b/src/niceload @@ -59,6 +59,8 @@ if(not defined $::opt_run_mem) { $::opt_run_mem = $::opt_mem; } if(not defined $::opt_start_noswap) { $::opt_start_noswap = $::opt_noswap; } if(not defined $::opt_run_noswap) { $::opt_run_noswap = $::opt_noswap; } +if(defined $::opt_load) { multiply_binary_prefix($::opt_load); } + my $limit = Limit->new(); my $process = Process->new($::opt_nice,@ARGV); if($::opt_pid) { @@ -89,6 +91,37 @@ while($process->is_alive()) { exit($::exitstatus); +sub multiply_binary_prefix { + # Evalualte numbers with binary prefix + # k=10^3, m=10^6, g=10^9, t=10^12, p=10^15, e=10^18, z=10^21, y=10^24 + # K=2^10, M=2^20, G=2^30, T=2^40, P=2^50, E=2^70, Z=2^80, Y=2^80 + # Ki=2^10, Mi=2^20, Gi=2^30, Ti=2^40, Pi=2^50, Ei=2^70, Zi=2^80, Yi=2^80 + # ki=2^10, mi=2^20, gi=2^30, ti=2^40, pi=2^50, ei=2^70, zi=2^80, yi=2^80 + # 13G = 13*1024*1024*1024 = 13958643712 + my $s = shift; + $s =~ s/k/*1000/g; + $s =~ s/M/*1000*1000/g; + $s =~ s/G/*1000*1000*1000/g; + $s =~ s/T/*1000*1000*1000*1000/g; + $s =~ s/P/*1000*1000*1000*1000*1000/g; + $s =~ s/E/*1000*1000*1000*1000*1000*1000/g; + $s =~ s/Z/*1000*1000*1000*1000*1000*1000*1000/g; + $s =~ s/Y/*1000*1000*1000*1000*1000*1000*1000*1000/g; + $s =~ s/X/*1000*1000*1000*1000*1000*1000*1000*1000*1000/g; + + $s =~ s/Ki?/*1024/gi; + $s =~ s/Mi?/*1024*1024/gi; + $s =~ s/Gi?/*1024*1024*1024/gi; + $s =~ s/Ti?/*1024*1024*1024*1024/gi; + $s =~ s/Pi?/*1024*1024*1024*1024*1024/gi; + $s =~ s/Ei?/*1024*1024*1024*1024*1024*1024/gi; + $s =~ s/Zi?/*1024*1024*1024*1024*1024*1024*1024/gi; + $s =~ s/Yi?/*1024*1024*1024*1024*1024*1024*1024*1024/gi; + $s =~ s/Xi?/*1024*1024*1024*1024*1024*1024*1024*1024*1024/gi; + $s = eval $s; + return $s; +} + sub get_options_from_array { # Run GetOptions on @array # Returns: @@ -109,6 +142,7 @@ sub get_options_from_array { "factor|f=s" => \$::opt_factor, "hard|H" => \$::opt_hard, "soft|S" => \$::opt_soft, + "sensor=s" => \$::opt_sensor, "si|sio|startio|start-io=s" => \$::opt_start_io, "ri|rio|runio|run-io=s" => \$::opt_run_io, @@ -541,17 +575,82 @@ sub sleep_while_running { } +# An non-blocking filehandle read that returns an array of lines read +# Returns: ($eof,@lines) +my %nonblockGetLines_last; +sub nonblockGetLines { + my ($fh,$timeout) = @_; + + $timeout = 0 unless defined $timeout; + my $rfd = ''; + $nonblockGetLines_last{$fh} = '' + unless defined $nonblockGetLines_last{$fh}; + + vec($rfd,fileno($fh),1) = 1; + return unless select($rfd, undef, undef, $timeout)>=0; + # I'm not sure the following is necessary? + return unless vec($rfd,fileno($fh),1); + my $buf = ''; + my $n = sysread($fh,$buf,1024*1024); + my $eof = eof($fh); + # If we're done, make sure to send the last unfinished line + return ($eof,$nonblockGetLines_last{$fh}) unless $n; + # Prepend the last unfinished line + $buf = $nonblockGetLines_last{$fh}.$buf; + # And save any newly unfinished lines + $nonblockGetLines_last{$fh} = + (substr($buf,-1) !~ /[\r\n]/ && $buf =~ s/([^\r\n]*)$//) + ? $1 : ''; + $buf ? ($eof,split(/\n/,$buf)) : ($eof); +} + +sub read_sensor { + my $self = shift; + my $fh = $self->{'sensor_fh'}; + if(not $fh) { + # Start the sensor + open($fh, "-|", $::opt_sensor) || ::die_bug("Cannot open: $::opt_sensor"); + $self->{'sensor_fh'} = $fh; + } + # Read as much as we can (non_block) + my ($eof,@lines) = nonblockGetLines($fh); + + # new load = last full line + foreach my $line ( @lines ) { + if(defined $line) { + print "Pipe saw: $eof [$line]\n"; + $Global::last_sensor_reading = $line; + } + } + if($eof) { undef($self->{'sensor_fh'}); } + + return $Global::last_sensor_reading; +} + sub load_status { # Returns: - # loadavg + # loadavg or sensor measurement my $self = shift; - # Cache for some seconds - if(not defined $self->{'load_status'} or - $self->{'load_status_cache_time'}+$self->{'recheck'} < time) { - $self->{'load_status'} = load_status_linux(); - $self->{'load_status_cache_time'} = time; + if($::opt_sensor) { + if(not defined $self->{'load_status'} or + $self->{'load_status_cache_time'} + $self->{'recheck'} < time) { + $self->{'load_status'} = $self->read_sensor(); + while (not defined $self->{'load_status'}) { + sleep 1; + $self->{'load_status'} = $self->read_sensor(); + } + $self->{'load_status_cache_time'} = time; + } + } else { + # Normal load avg + # Cache for some seconds + if(not defined $self->{'load_status'} or + $self->{'load_status_cache_time'} + $self->{'recheck'} < time) { + $self->{'load_status'} = load_status_linux(); + $self->{'load_status_cache_time'} = time; + } } - ::debug("load_status: $self->{'load_status'}\n"); + ::debug("load_status: ".$self->{'load_status'}."\n"); return $self->{'load_status'}; } diff --git a/src/niceload.pod b/src/niceload.pod index 502e5b8f..b7cddc4c 100644 --- a/src/niceload.pod +++ b/src/niceload.pod @@ -7,7 +7,8 @@ niceload - slow down a program when the load average is above a certain limit =head1 SYNOPSIS B [-v] [-h] [-n nice] [-I io] [-L load] [-M mem] [-N] -[-t time] [-s time|-f factor] ( command | -p PID ) +[--sensor program] [-t time] [-s time|-f factor] ( command | -p PID ) + =head1 DESCRIPTION @@ -131,6 +132,19 @@ Run limit. The running program will be slowed down if the system is above the limit. See: B<--io>, B<--load>, B<--mem>, B<--noswap>. +=item B<--sensor> I (alpha testing) + +Read sensor. Use I to read a sensor. + +This will keep the CPU temperature below 80 deg C on GNU/Linux: + + niceload -l 80000 -f 0.001 --sensor 'sort -n /sys/devices/platform/coretemp*/temp*_input' gzip * + +This will stop if the disk space < 100000. + + niceload -H -l -100000 --sensor "df . | awk '{ print \$4 }'" echo + + =item B<--start-io> I =item B<--si> I