Czy jest jakiś sposób, żeby na linuksie zliczać ile czasu procesora w jakimś przedziale czasu (np. tydzień) zjadły konkretne procesy ?
Wiadoma sprawa, jest np. 'top' ale podaje czas tylko podczas życia procesu.
Chciałbym natomiast prześledzić ile czasu na ten przykład w ciągu dnia zżerają procesy apacza, których zwykle uruchomionych jest około 100.
Ponadto chciałbym porównać schedulera w wersji 'cgi' - tu łatwo: top - z wersją fastcgi - tu już gorzej bo schedulerów jest kilka-kilkadziesiąt i są restartowane co X requestów.
Inaczej mówiąc - potrzebuję po prostu danych statystycznych co i jak wciąga mi moc maszyny, żebym wiedział co najpierw poprawiać %)
pidstat wchodzi w skład pakietu sysstat
ten pidstat jakoś dziwnie pokazuje
# pidstat -C search
Linux 2.6.26-2-amd64 (zeus) 07/26/2010 _x86_64_
04:23:00 PM PID %user %system %CPU CPU Command
04:23:00 PM 15173 4.60 0.00 4.61 3 search_2.06_i68
04:23:00 PM 19953 0.93 0.00 0.93 1 search_2.06_i68
04:23:00 PM 24042 10.51 0.00 10.51 2 search_2.06_i68
04:23:00 PM 30474 12.37 0.18 12.56 0 search_2.06_i68
a przecież te aplikacje wysycają każde jajo na ponad 90%
w międzyczasie skrobnąłem skrypt, bo mnie problem zaciekawił ;D
skrypt zbiera dane ze wszystkich uruchomionych procesów, zapisuje sobie te dane w pliku tymczasowym do ponownego wykorzystania...
przelicza dane, grupuje po nazwie procesu i wypluwa na ekran wynik...
trzeba go uruchamiać co jakiś czas... co 1 minutę będzie ok... :)
aby zacząć pomiar od nowa, wystarczy usunąć plik /tmp/sched.stat
(skrypt dla kernela 2.6.x)
#!/usr/bin/perl -w
# sched.pl
# 2010-07-24 by mindc
use strict;
use Data::Dumper;
use Fcntl qw(:flock);
my $fh;
my $stat = do ( '/tmp/sched.stat' ) || {};
foreach ( </proc/[0-9]*/sched> ) {
next if ! -r $_;
my ($pid) = $_ =~ m!/proc/(\d+)/sched!;
open $fh,"<",$_;
my @sched = get_exec_runtime($stat,$pid,$fh);
$stat->{"$sched[0]"}{$pid}{count}++;
$stat->{"$sched[0]"}{$pid}{weight} += $sched[1] ? $sched[2] / $sched[1] : 0;
$stat->{"$sched[0]"}{$pid}{avg} = $stat->{"$sched[0]"}{$pid}{weight} / $stat->{"$sched[0]"}{$pid}{count};
close $fh;
}
my $out = {};
foreach my $name ( keys %$stat ) {
foreach ( keys %{$stat->{$name}} ) {
$out->{$name}{count}++;
$out->{$name}{sum} += $stat->{$name}{$_}{avg};
$out->{$name}{avg} = $out->{$name}{sum} / $out->{$name}{count};
}
}
foreach ( sort { $out->{$b}{avg} <=> $out->{$a}{avg} } keys %$out ) {
next if $out->{$_}{avg} < .0001;
print "$_: ",sprintf("%.2f%%",$out->{$_}{avg}*100),"\n";
}
open $fh,">","/tmp/sched.stat";
flock $fh,LOCK_EX;
print $fh Dumper $stat;
flock $fh,LOCK_UN;
close $fh;
exit;
sub get_exec_runtime {
my ($ref,$pid,$fh,$name,$start,$runtime) = (shift,shift,shift,'',0,0);
while ( <$fh> ) {
$name = $1 if m/^(\S+)\s+\(\d/;
$start = $1 if m/se.exec_start\s*:\s*([0-9\.]+)$/;
$runtime = $1 if m/se.sum_exec_runtime\s*:\s*([0-9\.]+)$/;
}
$ref->{$name}{$pid}{starting_time} = $ref->{$name}{$pid}{starting_time} || $start;
$ref->{$name}{$pid}{starting_sum} = $ref->{$name}{$pid}{starting_sum} || $runtime;
return ($name,$start - $ref->{$name}{$pid}{starting_time},$runtime - $ref->{$name}{$pid}{starting_sum});
}
po kilku uruchomieniach:
search_2.06_i68: 90.66%
update.pl: 10.61%
ip.pl: 1.85%
mcedit: 0.84%
rtorrent: 0.81%
sched.pl: 0.48%
mount.ntfs-3g: 0.25%
boinc: 0.22%
freehalboinc_1.: 0.18%
kswapd0: 0.12%
data_collect_1.: 0.04%
nmap: 0.02%
xfslogd/0: 0.01%
vstatus.pl: 0.01%
events/0: 0.01%
Nie mam już sił tego dziś testować, bo padam na ryj, ale według mnie jest pewien problem - nawet przy wywoływaniu co 1s, większości krótkożyjących procesów nie będzie chyba doliczało. Takich np. procesów cgi/schedulera BOINCowego projektu potrafi spawnować i zniknąć w ciągu sekundy kilkanaście sztuk :D
no to żeby to ogarnąć to:
- napisać aplikację śledzącą wszystkie procesy, co 1ms... i... sama by zużywała przez to 100% CPU XD
- skoro jest dostęp do kodu źródłowego, to można dopisać kilka linijek, żeby procesy same logowały ile zużyły czasu CPU... byłby jednak pewien narzut czasu, tak czy siak... :ph34r:
TJM jeśli masz wątpliwości, czy zlicza wszystkie procesy wywołaj na przykład tak
pidstat -u -p ALL 10
jak widać trzeba odpalać pidstat w pętli, inaczej pokazuje jakieś babole...
można go spokojnie wykorzystać... jednak odpalony co 1s zużywa na moim sprzęcie od 2,6 do 5,2% CPU ( i tak lepiej niż wcześniejszy skrypt :/)
Trzeba korzystać z raportów (podsumowań średnich) a nie z cząstkowych wskazań. Inaczej wyjdą dziwaczne wyniki, obarczone błędem.
U mnie pidstat nie łyka procesora w ogóle, czasami w topie przewinie się gdzieś tak w połowie stawki. Maszyna rarytasem szybkościowym nie jest.
Sądzę że jeśli już modyfikować źródła, to raczej kernela żeby generował jakieś statystyki i zrzucał gdzieś np. do /proc. Niestety dla mnie to wyższa szkoła jazdy, kiedyś trochę dłubałem w kernelach ale za czasów 2.0.39 i 2.0.40-rc2 %)
Bez opcji -p (nie pojawiają się wtedy nic nie jedzące procesy) z raportowaniem np. co 30 minut mniej więcej daje to już jakiś obraz sytuacji, widać że od czasu do czasu dużo proca podkradają procesy, których w topie nie widać.