Śledzenie czasu procesora dla procesów

Zaczęty przez TJM, 26 Lipiec 2010, 09:37

TJM

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ć %)

W razie jakiejś pilniejszej sprawy - jestem często dostępny na kanale IRC B@P, na forum czasami zapominam zajrzeć lub nie mam czasu.

buninek

pidstat wchodzi w skład pakietu sysstat

mindc

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%




TJM

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

W razie jakiejś pilniejszej sprawy - jestem często dostępny na kanale IRC B@P, na forum czasami zapominam zajrzeć lub nie mam czasu.

mindc

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:


buninek

TJM jeśli masz wątpliwości, czy zlicza wszystkie procesy wywołaj na przykład tak

pidstat -u -p ALL 10

mindc

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 :/)


buninek

Trzeba korzystać z raportów (podsumowań średnich) a nie z cząstkowych wskazań. Inaczej wyjdą dziwaczne wyniki, obarczone błędem.

TJM

#8
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ć.

W razie jakiejś pilniejszej sprawy - jestem często dostępny na kanale IRC B@P, na forum czasami zapominam zajrzeć lub nie mam czasu.