1
0
mirror of https://github.com/wfjm/w11.git synced 2026-02-27 01:19:57 +00:00

finalize performance counter support

- rw11/dmpcnt.tcl: add pc_* procs to start and stop logger
- dmpcntanal: added, a script to analyse logger data
This commit is contained in:
wfjm
2018-10-30 15:14:55 +01:00
parent f903bda7b4
commit e29aa10096
4 changed files with 880 additions and 4 deletions

View File

@@ -44,7 +44,10 @@ The full set of tests is only run for tagged releases.
- download the `ghdl` based test benches (can't be build under Travis)
- execute the test benches with `tbrun`
- add KW11-P support, enable it in all w11a systems
- add pdp11_dmpcnt: performance counters
- add performance counters
- pdp11_dmpcnt: an array of 32 counters of 32 bit width
- connected to 24 signals from inside pdp11_sys70 and 8 signals from outside
- dmpcntanal: analysis script
### Changes
- Makefile: `make all_tcl` now quiet, use setup_packages_filt

506
tools/bin/dmpcntanal Executable file
View File

@@ -0,0 +1,506 @@
#!/usr/bin/perl -w
# $Id: dmpcntanal 1057 2018-10-19 15:06:42Z mueller $
#
# Copyright 2018- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
#
# This program is free software; you may redistribute and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for complete details.
#
# Revision History:
# Date Rev Version Comment
# 2018-10-19 1057 1.0 Initial version
# 2018-10-06 1053 0.1 First draft
#
use 5.14.0; # require Perl 5.14 or higher
use strict; # require strict checking
use Getopt::Long;
use Scalar::Util qw(looks_like_number);
my %opts = ();
GetOptions(\%opts, "cstate", "cevent", "clk", "cpi", "cpb",
"cache", "chit", "ibus", "rbus",
"raw=s@", "dat=s@", "fmt=s@", "sum=s@", "tot",
"cpu", "all", "hpl=i",
"help")
or die "bad options";
my %cnam2ind = (cpu_cpbusy => 0,
cpu_km_prix => 1,
cpu_km_pri0 => 2,
cpu_km_wait => 3,
cpu_sm => 4,
cpu_um => 5,
cpu_idec => 6,
cpu_pcload => 7,
cpu_vfetch => 8,
cpu_irupt => 9,
ca_rd => 10,
ca_wr => 11,
ca_rdhit => 12,
ca_wrhit => 13,
ca_rdmem => 14,
ca_wrmem => 15,
ca_rdwait => 16,
ca_wrwait => 17,
ib_rd => 18,
ib_wr => 19,
ib_busy => 20,
rb_rd => 21,
rb_wr => 22,
rb_busy => 23,
ext_rdrhit => 24,
ext_wrrhit => 25,
ext_wrflush => 26,
ext_rlrxact => 27,
ext_rlrxback => 28,
ext_rltxact => 29,
ext_rltxback => 20,
ext_usec => 31,
# calculated values
cpu_tot => -1, # total cpu cyles
cpu_act => -2, # active cpu cycles (no cp + wait)
ca_totwt => -3, # total cache wait cycles
ib_tot => -4, # total ibus requests
rb_tot => -5 # total rbus requests
);
my $sumdt = 0.4;
my @rawnam;
my @datnam;
my @fmtdsc;
my @sumdsc;
my %hraw;
my %hdif;
autoflush STDOUT 1 if (-p STDOUT); # autoflush if output into pipe
if (exists $opts{help}) {
print_help();
exit 0;
}
# process -raw and -dat options
foreach my $opt (@{$opts{raw}}) { push @rawnam, split /,/,$opt; }
foreach my $opt (@{$opts{dat}}) { push @datnam, split /,/,$opt; }
# process -fmt options
foreach my $opt (@{$opts{fmt}}) {
my @olist = split /,/,$opt;
if (scalar(@olist) < 4 || scalar(@olist) > 5) {
print STDERR "dmpcntanal-E: bad -fmt option '$opt'\n";
exit 1;
}
my $head = $olist[0];
my $fmt = $olist[1];
my $fac = $olist[2];
my $namnum = $olist[3];
my $namden = $olist[4];
$fac = 1. unless $fac ne '';
$fmt = '4.1' unless $fmt ne '';
my ($fmtlen,$fmtpre) = ($fmt =~ m/^(\d)\.(\d)$/);
unless (defined $fmtlen && defined $fmtpre) {
print STDERR "dmpcntanal-E: bad format '$fmt' in -fmt\n";
exit 1;
}
unless (length($head) <= $fmtlen) {
print STDERR "dmpcntanal-E: header '$head' longer than $fmtlen in -fmt\n";
exit 1;
}
chknum($fac, '-fmt');
chknam($namnum, '-fmt');
chknam($namden, '-fmt') if defined $namden;
push @fmtdsc, {head => $head,
fmt => '%' . $fmt .'f',
fmtlen => $fmtlen,
fmtpre => $fmtpre,
fac => $fac,
namnum => $namnum,
namden => $namden
};
}
# process -tot option
push @{$opts{sum}}, 'total' if $opts{tot};
# process -sum options
foreach my $opt (@{$opts{sum}}) {
my @olist = split /,/,$opt;
if (scalar(@olist) < 1 || scalar(@olist) > 3) {
print STDERR "dmpcntanal-E: bad -sum option '$opt'\n";
exit 1;
} else {
my $name = $olist[0];
my $from = $olist[1];
my $to = $olist[2];
unless (length($name) <= 6) {
print STDERR "dmpcntanal-E: name '$name' longer than 6 in -sum\n";
exit 1;
}
$from = 0. unless defined $from && $from ne '';
$to = 1.e8 unless defined $to && $to ne '';;
chknum($from, '-sum');
chknum($to, '-to');
if ($to <= $from) {
print STDERR "dmpcntanal-E: negative time interval [$from,$to] -sum\n";
exit 1;
}
push @sumdsc, {name => $name,
from => $from,
to => $to,
count => 0,
hdif => {}
};
}
}
foreach my $nam (@rawnam) { chknam($nam, '-raw') }
foreach my $nam (@datnam) { chknam($nam, '-dat') }
# process -cache and -chit options
delete $opts{chit} if $opts{cache}; # hide -chit if -cache given
# default to -cpu if no field specified
unless ($opts{cstate} || $opts{cevent} ||
$opts{clk} || $opts{cpi} || $opts{cpb} ||
$opts{cache} || $opts{chit} || $opts{ibus} || $opts{rbus} ||
$opts{cpu} || $opts{all} ||
scalar(@rawnam) || scalar(@datnam) || scalar(@fmtdsc)) {
$opts{cpu} = 1;
}
# process -cpu
if ($opts{cpu}) {
$opts{cstate} = 1;
$opts{cevent} = 1;
$opts{chit} = 1;
}
# process -all
if ($opts{all}) {
$opts{cstate} = 1;
$opts{cevent} = 1;
$opts{cache} = 1;
$opts{ibus} = 1;
$opts{rbus} = 1;
}
# and finally process data
foreach my $file (@ARGV) {
read_file($file);
}
#-------------------------------------------------------------------------------
sub read_file {
my ($file) = @_;
# print headers
prthead();
# open file
open IFILE,"<$file" or die "failed to open $file";
my @vraw = (0) x 32;
my @vdif = (0) x 32;
my @vlast = (0) x 32;
my $nline = 0;
# loop over lines in file
while (<IFILE>) {
chomp;
next if m/^#/;
if (m/^\s*(\d+\.\d+)\s+((\s*\d+){32})$/x) {
# prepare data as array
my $time = $1;
my @vraw = split /\s+/,$2;
for (my $i=0; $i<32; $i++) {
my $dif = $vraw[$i] - $vlast[$i];
$dif += 4.*1024.*1024.*1024. if ($dif < 0);
$vdif[$i] = $dif;
$vlast[$i] = $vraw[$i];
}
# prepare data as hash
foreach my $nam (keys %cnam2ind) {
next if $cnam2ind{$nam} < 0;
$hraw{$nam} = $vraw[$cnam2ind{$nam}];
$hdif{$nam} = $vdif[$cnam2ind{$nam}];
}
$hdif{cpu_tot} = $hdif{cpu_cpbusy} + $hdif{cpu_km_prix} +
$hdif{cpu_km_pri0} + $hdif{cpu_km_wait} +
$hdif{cpu_sm} + $hdif{cpu_um};
$hdif{cpu_act} = $hdif{cpu_km_prix} + $hdif{cpu_km_pri0} +
$hdif{cpu_sm} + $hdif{cpu_um};
$hdif{ca_totwt} = $hdif{ca_rdwait} + $hdif{ca_wrwait};
$hdif{ib_tot} = $hdif{ib_rd} + $hdif{ib_wr};
$hdif{rb_tot} = $hdif{rb_rd} + $hdif{rb_wr};
# accululation of (sub-)totals
foreach my $dsc (@sumdsc) {
if ($time >= $dsc->{from}-$sumdt && $time <= $dsc->{to}+$sumdt) {
$dsc->{count} += 1;
foreach my $k (keys %hdif) { $dsc->{hdif}->{$k} += $hdif{$k} }
}
}
# do printing
$nline += 1;
if ($opts{hpl} && $opts{hpl} > 0 && $nline > $opts{hpl}) {
print "\n";
prthead();
$nline = 0;
}
prtline(\%hraw, \%hdif, (sprintf "%6.1f", $time));
} else {
printf STDERR "bad line: $_\n";
}
}
# print (sub-)totals
if (scalar @sumdsc) {
print "\n";
prthead();
foreach my $dsc (@sumdsc) {
if ($dsc->{count} > 0) {
foreach my $k (keys %hdif) { $dsc->{hdif}->{$k} /= $dsc->{count} }
prtline(undef, $dsc->{hdif}, $dsc->{name});
} else {
printf "%6s ... empty ... no data in [%4.1f,%4.1f]\n",
$dsc->{name}, $dsc->{from}-$sumdt, $dsc->{to}+$sumdt;
}
}
}
close IFILE;
}
#-------------------------------------------------------------------------------
sub prtline {
my ($rhraw,$rhdif,$tcol) = @_;
printf "%6s", $tcol;
if (defined $rhraw) {
foreach my $nam (@rawnam) { printf " %10.0f", $rhraw->{$nam}; }
} else {
foreach my $nam (@rawnam) { printf ' ' x 10 . '-'; }
}
foreach my $nam (@datnam) { printf " %9.0f", $rhdif->{$nam}; }
if ($opts{cstate}) {
print ' ';
prtrat($rhdif,'%4.1f',100.,'cpu_cpbusy','cpu_tot');
prtrat($rhdif,'%4.1f',100.,'cpu_km_prix','cpu_tot');
prtrat($rhdif,'%4.1f',100.,'cpu_km_pri0','cpu_tot');
prtrat($rhdif,'%4.1f',100.,'cpu_km_wait','cpu_tot');
prtrat($rhdif,'%4.1f',100.,'cpu_sm','cpu_tot');
prtrat($rhdif,'%4.1f',100.,'cpu_um','cpu_tot');
}
if ($opts{clk}) {
prtval($rhdif,'%5.1f',1.e-6,'cpu_tot');
}
if ($opts{cevent}) {
print ' ';
prtval($rhdif,'%5.2f',1.e-6,'cpu_idec');
prtval($rhdif,'%5.0f',1.,'cpu_vfetch');
prtval($rhdif,'%5.0f',1.,'cpu_irupt');
prtrat($rhdif,'%4.1f',1.,'cpu_idec','cpu_pcload');
}
if ($opts{cpi}) {
prtrat($rhdif,'%4.1f',1.,'cpu_act','cpu_idec');
}
if ($opts{cpb}) {
prtrat($rhdif,'%4.1f',1.,'cpu_act','cpu_pcload');
}
if ($opts{cache}) {
print ' ';
prtrat($rhdif,'%4.2f',1.,'ca_rd','cpu_idec');
prtrat($rhdif,'%4.2f',1.,'ca_wr','cpu_idec');
prtrat($rhdif,'%4.1f',100.,'ca_rdhit','ca_rd');
prtrat($rhdif,'%4.1f',100.,'ca_wrhit','ca_wr');
prtrat($rhdif,'%4.1f',1.,'ca_rdwait','ca_rdmem');
prtrat($rhdif,'%4.1f',1.,'ca_wrwait','ca_wrmem');
prtrat($rhdif,'%4.1f',1.,'ca_totwt','cpu_idec');
}
if ($opts{chit}) {
print ' ';
prtrat($rhdif,'%4.1f',100.,'ca_rdhit','ca_rd');
prtrat($rhdif,'%4.1f',100.,'ca_wrhit','ca_wr');
prtrat($rhdif,'%4.1f',1.,'ca_totwt','cpu_idec');
}
if ($opts{ibus}) {
print ' ';
prtval($rhdif,'%4.2f',1.e-3,'ib_rd');
prtval($rhdif,'%4.2f',1.e-3,'ib_wr');
prtrat($rhdif,'%4.1f',1.,'ib_busy','ib_tot');
}
if ($opts{rbus}) {
print ' ';
prtval($rhdif,'%4.2f',1.e-3,'rb_rd');
prtval($rhdif,'%4.2f',1.e-3,'rb_wr');
prtrat($rhdif,'%4.1f',1.,'rb_busy','rb_tot');
}
foreach my $dsc (@fmtdsc) {
if (defined $dsc->{namden}) {
prtrat($rhdif, $dsc->{fmt}, $dsc->{fac}, $dsc->{namnum}, $dsc->{namden});
} else {
prtval($rhdif, $dsc->{fmt}, $dsc->{fac}, $dsc->{namnum});
}
}
printf "\n";
}
#-------------------------------------------------------------------------------
sub prthead {
# print header line 1
printf ' time';
foreach my $nam (@rawnam) { printf " %9s_", (split /_/,$nam,2)[0]; }
foreach my $nam (@datnam) { printf " %8s_", (split /_/,$nam,2)[0];}
print ' ------ cpu state in % -------' if $opts{cstate};
print ' clock' if $opts{clk};
print ' ----- cpu events -----' if $opts{cevent};
print ' ----' if $opts{cpi};
print ' ----' if $opts{cpb};
print ' -------------- cache -------------' if $opts{cache};
print ' ---- cache ---' if $opts{chit};
print ' ---- ibus ----' if $opts{ibus};
print ' ---- rbus ----' if $opts{rbus};
my $fmtcol = 0;
foreach my $dsc (@fmtdsc) { $fmtcol += $dsc->{fmtlen}+1 }
if ($fmtcol > 0) {
my $ndash = $fmtcol - 6;
my $nleft = int($ndash/2);
my $nright = $ndash - $nleft;
print ' ' . '-'x$nleft . ' fmt ' . '-'x$nright;
}
printf "\n";
# print header line 2
printf " sec";
foreach my $nam (@rawnam) { printf " %10s", (split /_/,$nam,2)[1]; }
foreach my $nam (@datnam) { printf " %9s", (split /_/,$nam,2)[1]; }
print ' cp km>0 km=0 wait sm um' if $opts{cstate};
print ' MHz' if $opts{clk};
print ' Min/s vfetc irupt i/b' if $opts{cevent};
print ' c/i' if $opts{cpi};
print ' c/b' if $opts{cpb};
print ' r/i w/i rhit whit rwt wwt wt/i' if $opts{cache};
print ' rhit whit wt/i' if $opts{chit};
print ' rdkH wrkH wt/r' if $opts{ibus};
print ' rdkH wrkH wt/r' if $opts{rbus};
foreach my $dsc (@fmtdsc) { printf " %$dsc->{fmtlen}s", $dsc->{head}}
printf "\n";
}
#-------------------------------------------------------------------------------
sub prtrat {
my ($rhdif,$fmt,$mul,$namnum,$namden) = @_;
if (not exists $rhdif->{$namnum} || not exists $rhdif->{$namden}) {
prtbad($fmt);
} else {
my $rat = 0.;
$rat = $rhdif->{$namnum} / $rhdif->{$namden} if $rhdif->{$namden} > 0.;
prtfmt($fmt, $rat*$mul);
}
}
#-------------------------------------------------------------------------------
sub prtval {
my ($rhdif,$fmt,$mul,$nam) = @_;
if (not exists $rhdif->{$nam}) {
prtbad($fmt);
} else {
prtfmt($fmt, $rhdif->{$nam}*$mul);
}
}
#-------------------------------------------------------------------------------
sub prtfmt {
my ($fmt,$val) = @_;
my ($len,$prec) = ($fmt =~ m/(\d)\.(\d)/);
my $str = sprintf $fmt, $val;
if (($prec == 0 && length($str) > $len) ||
($prec > 0 && length($str) > $len+$prec+1)) {
print ' ' . '*' x $len;
return
}
$str = substr($str,0,$len) if length($str) > $len;
print ' ' . $str;
}
#-------------------------------------------------------------------------------
sub prtbad {
my ($fmt) = @_;
my ($len,$prec) = ($fmt =~ m/(\d)\.(\d)/);
print ' ' x $len . '-';
}
#-------------------------------------------------------------------------------
sub chknam {
my ($nam,$cmd) = @_;
return if exists $cnam2ind{$nam};
print STDERR "dmpcntanal-E: unknown counter name '$nam' in $cmd\n";
exit 1;
}
#-------------------------------------------------------------------------------
sub chknum {
my ($num,$cmd) = @_;
return if looks_like_number($num);
print STDERR "dmpcntanal-E: bad factor '$num' in $cmd\n";
exit 1;
}
#-------------------------------------------------------------------------------
sub print_help {
print "usage: dmpcntanal file\n";
print " --cstate show cpu state colums\n";
print " --cevent show cpu events colums\n";
print " --clk show cpu clock column\n";
print " --cpi show cpu cycle/instruction column\n";
print " --cpb show cpu cycle/branch column\n";
print " --cache show all cache colums\n";
print " --chit show cache hit+wait colums (subset of --cache)\n";
print " --ibus show ibus colums\n";
print " --rbus show rbus colums\n";
print " --raw=c[,c,..] show raw data of counter c\n";
print " --dat=c[,c,..] show rate data of counter c\n";
print " --fmt=h,f,m,n[,d] add custom colum with\n";
print " h header text\n";
print " f format as len.pre (default 4.1)\n";
print " m multiplier (default 1.)\n";
print " n numerator counter name\n";
print " d denominator counter name (optional)\n";
print " --sum=n[,f[,t]] add sub-total line, with\n";
print " n name printed in time column\n";
print " f from, begin of interval (optional)\n";
print " t to, end of interval (optional)\n";
print " --tot add total line (short for -sum=total)\n";
print " --cpu short for -cstate -cevent -chit (default view)\n";
print " --all short for -cstate -cevent -cache -ibus -rbus\n";
print " --hpl=n print header after n lines\n";
print " --help this message\n";
}

282
tools/man/man1/dmpcntanal.1 Normal file
View File

@@ -0,0 +1,282 @@
.\" -*- nroff -*-
.\" $Id: dmpcntanal.1 1059 2018-10-27 10:34:16Z mueller $
.\"
.\" Copyright 2018- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
.\"
.\" ------------------------------------------------------------------
.
.TH DMPCNTANAL 1 2018-10-21 "Retro Project" "Retro Project Manual"
.\" ------------------------------------------------------------------
.SH NAME
dmpcntanal \- analyze dmpcnt data
.\" ------------------------------------------------------------------
.SH SYNOPSIS
.
.SY dmpcntanal
.RI [ OPTION ]...
.I FILE
.
.SY dmpcntanal
.B \-\-help
.YS
.
.\" ------------------------------------------------------------------
.SH DESCRIPTION
Reads a list of CPU performance counter raw data, usually generated via
a \fIrw11::pc_lsta\fR command, and generates human readable reports.
.
.\" ------------------------------------------------------------------
.SH OPTIONS
.
.\" ----------------------------------------------
.IP "\fB\-\-cstate\fR"
show the CPU state columns, which give in percent the fraction of
clock cycles spend in different CPU states:
.RS
.IP \fIcp\fP
console port handling, mostly rbus processing.
.PD 0
.IP \fIkm>0\fP
kernel mode at priority > 0, interrupt handling or interrupt lock-out
.IP \fIkm=0\fP
kernel mode at priority == 0
.IP \fIwait\fP
idling in a WAIT instruction
.IP \fIsm\fP
supervisor mode
.IP \fIsum\fP
user mode
.PD
.RE
.
.\" ----------------------------------------------
.IP "\fB\-\-cevents\fR"
show the CPU events columns
.RS
.IP \fIMin/s\fP
instruction rate in MHz
.PD 0
.IP \fIvfetc\fP
vector fetch rate, sum of traps, exceptions and interrupts.
.IP \fIirupt\fP
interrupt rate
.IP \fIi/b\fP
instruction per branch
.PD
.RE
.
.\" ----------------------------------------------
.IP "\fB\-\-clk\fR"
clock rate on MHz, counting only cycles when CPU running. In normal
operation this is equivalent to the system clock rate.
.
.\" ----------------------------------------------
.IP "\fB\-\-cpi\fR"
show the CPU cycle/instruction column.
.
.\" ----------------------------------------------
.IP "\fB\-\-cpb\fR"
show the CPU cycle/branch column.
.
.\" ----------------------------------------------
.IP "\fB\-\-cache\fR"
show all cache columns.
.RS
.IP \fIr/i\fP
number of read requests per instruction.
.PD 0
.IP \fIw/i\fP
number of write requests per instruction.
.IP \fIrhit\fP
read hit rate in %.
.IP \fIwhit\fP
write hit rate in %.
.IP \fIrwt\fP
average number of wait cycles per memory read (in miss case).
.IP \fIwwt\fP
average number of wait cycles per memory write (from back pressure).
.IP \fIwt/i\fP
average number of memory wait cycles per instruction.
.PD
.RE
.
.\" ----------------------------------------------
.IP "\fB\-\-chit\fR"
show cache columns \fIrhit\fP, \fIwhit\fP and \fIwt/i\fP, subset of
\fB--cache\fR.
.
.\" ----------------------------------------------
.IP "\fB\-\-ibus\fR"
show all ibus columns.
.RS
.IP \fIrdkH\fP
ibus read rate in kHz.
.PD 0
.IP \fIwrkH\fP
ibus write rate in kHz.
.IP \fIwt/r\fP
average number of ibus wait cycles (read and write combined).
.PD
.RE
.
.\" ----------------------------------------------
.IP "\fB\-\-rbus\fR"
show all rbus columns.
.RS
.IP \fIrdkH\fP
ibus read rate in kHz.
.PD 0
.IP \fIwrkH\fP
ibus write rate in kHz.
.IP \fIwt/r\fP
average number of ibus wait cycles (read and write combined).
.PD
.RE
.
.\" ----------------------------------------------
.IP "\fB\-\-raw\fR=\fIclist\fR"
show raw data of the counters given in the comma separated list of
counter names \fIclist\fR.
.
.\" ----------------------------------------------
.IP "\fB\-\-dat\fR=\fIclist\fR"
show data rate of the counters given in the comma separated list of
counter names \fIclist\fR.
.
.\" ----------------------------------------------
.IP "\fB\-\-fmt\fR=\fIhdr,[fmt],[mul],num[,den]\fR"
add custom column with a scaled counter rate or a scaled counter ratio
specified with
.RS
.IP \fBhdr\fP
text for header. The length if the header must be equal or less than the
width of the format.
.PD 0
.IP \fBfmt\fP
format in the form like \fIw.p\fR with a single digit field width \fIw\fR
and single digit precision \fIp\fR. If \fIp\fR is \fI0\fR no decimal point
is printed. If omitted \fI4.1\fR is assumed.
.IP \fBmul\fP
multiplier, given as integer of floating point number.
If omitted 1. is assumed.
.IP \fBnum\fP
name of numerator counter
.IP \fBden\fP
name of denominator counter. If specified the ratio \fInum/den\fR is
printed, if omitted the rate \fInum\fR is printed.
.PD
.RE
.
.\" ----------------------------------------------
.IP "\fB\-\-sum\fR=\fInam[,from[,to]]\fR"
allows to determine averages for a given time interval with
.RS
.IP \fBnam\fP
name printed in the 1st column, up to 6 characters allowed.
.PD 0
.IP \fBfrom\fP
start time of averaging, if omitted start at begin.
.IP \fBto\fP
end time of averaging, if omitted sum to the end.
.PD
.RE
.
.\" ----------------------------------------------
.IP "\fB\-\-tot\fR"
add line with average values for the whole dataset, short for \fB-sum=total\fR.
.
.\" ----------------------------------------------
.IP "\fB\-\-cpu\fR"
short for \fB-cstate -cevent -chit\fR. If no option which generates
an output column is given and a \fB\-cpu\fR style output is generated.
.
.\" ----------------------------------------------
.IP "\fB\-\-all\fR"
short for \fB-cstate -cevent -cache -ibus -rbus\fR.
.
.\" ----------------------------------------------
.IP "\fB\-\-hpl\fR=\fIn\fR"
print header after \fIn\fR lines.
.
.\" ----------------------------------------------
.IP "\fB\-\-help\fR"
print full help text and exit.
.
.\" ------------------------------------------------------------------
.SH COLUMN DEFINITIONS
All standard columns generated via options like \fB-cstate\fR can
also be created via the \fB-fmt\fR option with the following parameters
.EX
name format mul numerator denominator
cp 4.1 100. cpu_cpbusy cpu_tot
km>0 4.1 100. cpu_km_prix cpu_tot
km=0 4.1 100. cpu_km_pri0 cpu_tot
wait 4.1 100. cpu_km_wait cpu_tot
sm 4.1 100. cpu_sm cpu_tot
um 4.1 100. cpu_um cpu_tot
Min/s 5.2 1.e-6 cpu_idec
vfetch 5.0 1. cpu_vfetch
irupt 5.0 1. cpu_irupt
i/b 4.1 1. cpu_idec cpu_pcload
r/i 4.2 1. ca_rd cpu_idec
w/i 4.2 1. ca_wr cpu_idec
rhit 4.1 100. ca_rdhit ca_rd
whit 4.1 100. ca_wrhit ca_wr
rwt 4.1 1. ca_rdwait ca_rdmem
wwt 4.1 1. ca_wrwait ca_wrmem
wt/i 4.1 1. ca_totwt cpu_idec
rdkH 4.2 1.e-3 ib_rd
wrkH 4.2 1.e-3 ib_wr
wt/r 4.1 1. ib_busy ib_tot
rdkH 4.2 1.e-3 rb_rd
wrkH 4.2 1.e-3 rb_wr
wt/r 4.1 1. rb_busy rb_tot
.EE
.\" ------------------------------------------------------------------
.SH EXAMPLES
.IP "\fBdmpcntanal -cstate -cevent -tot pc_dmpcnt_xxx.dat\fR" 4
reads the file \fIpc_dmpcnt_xxx.dat\fR and generates a report with the
\fB-cstate\fR and \fB-cevent\fR columns sets.
The input file is typically generated by a \fBti_w11\fR tcl command like
.EX
rw11::pc_clear
rw11::pc_start
rw11::pc_lsta pc_dmpcnt_xxx.dat
.EE
The output might look like
.EX
time ------ cpu state in % ------- ----- cpu events -----
sec cp km>0 km=0 wait sm um Min/s vfetc irupt i/b
...
38.0 0.7 10.4 19.2 4.0 0.0 65.7 8.95 1319 712 4.2
39.0 0.4 5.1 9.9 1.4 0.0 83.1 9.76 1021 373 4.0
40.0 0.7 9.4 18.6 3.6 0.0 67.8 8.60 1135 616 4.5
41.0 0.4 4.6 9.5 1.1 0.0 84.4 9.81 1190 313 4.1
42.0 0.6 7.1 18.0 3.4 0.0 70.8 9.33 1153 611 3.9
43.0 0.5 7.6 15.0 4.1 0.0 72.7 9.15 1278 540 4.1
44.0 0.6 9.2 15.8 3.0 0.0 71.4 8.87 1267 509 4.4
45.0 0.6 7.4 16.7 3.2 0.0 72.1 8.96 1276 552 4.2
...
time ------ cpu state in % ------- ----- cpu events -----
sec cp km>0 km=0 wait sm um Min/s vfetc irupt i/b
total 0.5 7.0 17.0 19.7 0.0 55.8 7.28 1453 471 3.9
.EE
.\" ------------------------------------------------------------------
.SH "SEE ALSO"
.BR ti_w11 (1)
.\" ------------------------------------------------------------------
.SH AUTHOR
Walter F.J. Mueller <W.F.J.Mueller@gsi.de>

View File

@@ -1,4 +1,4 @@
# $Id: dmpcnt.tcl 1056 2018-10-13 16:01:17Z mueller $
# $Id: dmpcnt.tcl 1058 2018-10-21 21:46:26Z mueller $
#
# Copyright 2018- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
#
@@ -13,6 +13,7 @@
#
# Revision History:
# Date Rev Version Comment
# 2018-10-21 1058 1.1 add logger, pc_l* commands
# 2018-10-13 1055 1.0 Initial version
# 2018-09-23 1050 0.1 First draft
#
@@ -30,7 +31,7 @@ namespace eval rw11 {
{func 2 3 "s:NOOP:NOOP1:NOOP2:NOOP3:STO:STA:CLR:LOA"}
regdsc PC_STAT {ainc 15} {caddr 13 5} {waddr 8} {run 0}
# preliminary handling of counter names, hack in first version
# preliminary handling of counter names, hack in first version
variable pcnt_cnames [list cpu_cpbusy cpu_km_prix cpu_km_pri0 cpu_km_wait \
cpu_sm cpu_um cpu_idec cpu_pcload \
cpu_vfetch cpu_irupt ca_rd ca_wr \
@@ -46,7 +47,12 @@ namespace eval rw11 {
incr tmp_ind
}
unset tmp_ind
variable pcnt_timesta 0
variable pcnt_timenext 0
variable pcnt_logaftid 0
variable pcnt_logchan 0
#
# pc_setup: rmap definitions for dmpcnt
#
@@ -126,5 +132,84 @@ namespace eval rw11 {
}
return $rval
}
#
# pc_lsta: start logging
#
proc pc_lsta {{file ""}} {
variable pcnt_timesta
variable pcnt_timenext
variable pcnt_logaftid
variable pcnt_logchan
if {$pcnt_logchan != 0} { error "pc logger already running" }
if {$file eq ""} {
set timestamp [clock format [clock seconds] -format "%Y-%m-%d-%H%M%S"]
set file "pc_dmpcnt$timestamp.dat"
}
pc_clear
pc_start
set pcnt_logchan [open $file w]
fconfigure $pcnt_logchan -buffering line
set pcnt_timesta [clock milliseconds]
set pcnt_timenext $pcnt_timesta
after 0 rw11::pc_lhdl
return ""
}
#
# pc_lsto: stop logging
#
proc pc_lsto {} {
variable pcnt_logaftid
variable pcnt_logchan
variable pcnt_timesta
variable pcnt_timenext
if {$pcnt_logchan == 0} { return "" }
after cancel $pcnt_logaftid
close $pcnt_logchan
set pcnt_logchan 0
set pcnt_timesta 0
set pcnt_timenext 0
set pcnt_logaftid 0
return ""
}
#
# pc_lcom: add comment to logger
#
proc pc_lcom {{comment ""}} {
variable pcnt_logchan
if {$pcnt_logchan == 0} { error "pc logger not running" }
puts $pcnt_logchan "# $comment"
return ""
}
#
# pc_lhdl: logger handler
#
proc pc_lhdl {} {
variable pcnt_timesta
variable pcnt_timenext
variable pcnt_logaftid
variable pcnt_logchan
if {$pcnt_logchan == 0} { return "" }
set tela [expr {([clock milliseconds]-$pcnt_timesta)/1000.}]
set pclist [pc_read]
set line [format "%10.3f " $tela]
foreach {pc} $pclist {
append line [format " %1.0f" $pc]
}
puts $pcnt_logchan $line
set pcnt_timenext [expr {$pcnt_timenext + 1000}]
set dt [expr { $pcnt_timenext - [clock milliseconds]}]
after $dt rw11::pc_lhdl
return ""
}
}