#!

/usr/bin/perl
#
# prustat - Process utilisation stats: %CPU, %Mem, %Disk, %Net. Solaris 10.
#
Needs to run as root. This is a demonstration release - check for
#
newer optimised versions. Uses Kstat, DTrace and procfs.
#
# 12-Mar-2005, ver 0.50 (demonstration release, http://www.brendangregg.com)
#
#
# USAGE:
#
prustat [-cehinuwxz] [-p PID] [-s sort] [-t top] [interval] [count]
#
#
prustat
# %Utilisation
#
prustat -i
# + I/O stats
#
prustat -u
# + USR/SYS times
#
prustat -x
# + Context Switchs
#
prustat -c
# Clear screen
#
prustat -w
# Wide output
#
prustat -z
# Skip zero lines
#
prustat -e
# Extra precision
#
prustat -p PID
# this PID only
#
prustat -s sort
# sort on pid|cpu|mem|disk|net|utime|vctx|...
#
prustat -t lines
# print top number of lines only
# eg,
#
prustat 2
# 2 second samples (first is historical)
#
prustat 10 5
# 5 x 10 second samples
#
prustat -t 8 10 5
# 5 x 10 second samples, top 8 lines only
#
prustat -ct 20 5
# 20 lines with screen refresh each 5 seconds
#
prustat -iuxct 5 10
# multi output, all reports every 10 seconds
#
prustat -ct 22 -s cpu 5 # 22 lines, sort by cpu, every 5 secs
#
prustat -ct 22 -s mem 5 # 22 lines, sort by mem, every 5 secs
#
prustat -ct 22 -s net 5 # 22 lines, sort by network, every 5 secs
#
prustat -ct 22 -s disk 5 # 22 lines, sort by disk, every 5 secs
#
# FIELDS:
#
PID
Process ID
#
CPU
Percent CPU
#
Mem
Percent RAM
#
Disk
Percent Disk
#
Net
Percent Network
#
MAJF
Major Page Faults (disk I/O)
#
INBLK In Blocks (disk I/O reads)
#
OUBLK Out Blocks (disk I/O writes)
#
CHAR-kb Character I/O Kbytes
#
COMM
Command name
#
USR
User Time
#
SYS
System Time
#
WAIT
Wait for CPU Time
#
VCTX
Voluntary Context Switches (I/O bound)
#
ICTX
Involuntary Context Switches (CPU bound)
#
SYSC
System calls
#
# WARNING: This program will run DTrace to gather Disk and Network data.
#
This has not been fully tested on different environments to study the
#
impact of these extra measurements. For now this is a demonstration
#
release - best to run in development for short periods. Check for
#
newer versions and updates to this message.
#
# NOTE: There is no historical values for Disk or Network utilisation percent,
#
the first sample for these will always show zero.

Extra precision multi report. prusage socketsnoop. Boston. $TARGET_PID = -1. # # --. utilisation output style.d prstat -m # process Disk I/O # process TCP # USR/SYS times. $count = 1. ns current iteration default NIC speed (100 Mbps) ### Network card instance names @Network = qw(dmfe bge be ce eri ge hme le ppp qfe rtls sppp iprb). $TOP = 0. This program is distributed in the hope that it will be useful. Context Switches output style. $STYLE_CTX = 0. --# # # # # # # # # # # # # # # # # # # seconds to sample max count of samples skip summary output (new data only) print wide output (don't truncate) print PID 0 print top many only clear screen before outputs if 1. $STYLE_EXTRA = 0. Inc. without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. skip zero entries (all 0. use Sun::Solaris::Kstat. USA.Suite 330. $TIME_BEGIN = 1. I/O output style. $ZERO = 0. either version 2 or (at your option) any later version. $STYLE_TIME = 0. if not. (http://www.org/copyleft/gpl. psio.Default Variables # $INTERVAL = 1. $Network{$_} = 1 foreach (@Network). See the GNU General Public License for more details. MA 02111-1307. $WIDE = 0. write to the Free Software Foundation. $MAX = 1. $MULTI = 0. use Getopt::Std. $STYLE_IO = 0. $SCHED = 0. but WITHOUT ANY WARRANTY.gnu. This program is modify it under as published by of the License. $NIC_DEF = 100_000_000. $STYLE_UTIL = 1. . . $NEW = 0. Australia] 12-Mar-2005 Brendan Gregg Created this.. you can redistribute it and/or the terms of the GNU General Public License the Free Software Foundation.h SEE ALSO: iosnoop. ns end of interval. Times output style.. COPYRIGHT: Copyright (c) 2005 Brendan Gregg. multiple styles target PID. 59 Temple Place . free software.00) default output style.. $CLEAR = 0. -1 means all start of interval. You should have received a copy of the GNU General Public License along with this program.html) Author: Brendan Gregg [Sydney. my $Kstat = Sun::Solaris::Kstat->new(). $TIME_END = 1.# # # # # # # # # # # # # # # # # # # # # # # # # # # # REFERENCES: /usr/include/sys/procfs.

my ($bytes.Open DTrace --# @Dscript = <DATA>. $SORT = $opt_s if defined $opt_s.$rbytes. if (defined $$Names{ifspeed}) { $NIC_SPEED += $$Names{ifspeed}. $Modules = $Kstat->{$module}. # # --. $STYLE_UTIL = 0 if $opt_i || $opt_x || $opt_u || $opt_e. $CLEARSTR = `clear` if $CLEAR. $MAX = 2**32 if @ARGV == 1. $STYLE_EXTRA = 1 if $opt_e. $STYLE_IO = 1 if $opt_i. $CLEAR = 1 if $opt_c.%Names). $INTERVAL = shift(@ARGV) || $INTERVAL. # sum of Mbps across all NICs ### Loop over all NICs foreach $module (keys(%$Kstat)) { next unless $Network{$module}. foreach $name (keys(%$Instances)) { $Names = $Instances->{$name}.# # --. $NIC_SPEED = 0. $TARGET_PID = $opt_p if defined $opt_p. .$time.$module. $NEW = 1 if $opt_n.@Dscript).Command Line Arguments --# &Usage() if $ARGV[0] eq "--help".$instance.%Instances. # # --. $MAX = shift(@ARGV) || $MAX. foreach $instance (keys(%$Modules)) { $Instances = $Modules->{$instance}. &Usage() if $opt_h. $MULTI = 1 if ($STYLE_IO + $STYLE_CTX + $STYLE_TIME) > 1. $STYLE_TIME = 1 if $opt_u. } } } } $NIC_SPEED = $NIC_DEF if $NIC_SPEED == 0. $TOP = $opt_t if defined $opt_t. my (%Modules.$wbytes). $STYLE_CTX = 1 if $opt_x.Determine Network Capacity --# my ($error. getopts('cehinuwxzp:s:t:') || &Usage(). } else { $NIC_SPEED += $NIC_SPEED.$name). $dscript = join(''. $WIDE = 1 if $opt_w. $ZERO = 1 if $opt_z. $STYLE_IO = 1 if $opt_i.

$SIG{PIPE} = ###BOT_TEXT###amp;Cleanup.Main --# for (. $pause++) { &GetDTraceStat(). ### Cleanup memory undef %Comm. $SIG{QUIT} = ###BOT_TEXT###amp;Cleanup. # This can be run multiple times. ### Get Disk and Net data for ($pause = 0. $pause < $INTERVAL. } } close(DTRACE). chdir "/proc".open(DTRACE. &PrintIO($SORT) if $STYLE_IO. $SIG{TERM} = ###BOT_TEXT###amp;Cleanup. undef %PID. ### Cleanup on signals $SIG{INT} = ###BOT_TEXT###amp;Cleanup. &PrintTime($SORT) if $STYLE_TIME. next if $NEW && $count == 1. # # --. # # --. the first time %PID will be # populated with the summary since boot values. # sub GetProcStat { my $pid.Gets /proc usage statistics and saves them in %PID. &PrintUtil($SORT) if $STYLE_UTIL.Subroutines --# # GetProcStat ."$dscript 2>/dev/null |") || die("ERROR1: Can't open dtrace: $!\n"). # This reads /proc/*/usage and /proc/*/prstat. $count++) { ### Get CPU and Mem data &GetProcStat(). &PrintExtra($SORT) if $STYLE_EXTRA. $TIME_BEGIN = $TIME_END. ### Print data print $CLEARSTR if $CLEAR. ### Preprocess PID &ProcessPID(). . &PrintCtx($SORT) if $STYLE_CTX.$count <= $MAX. ### Main PID Loop foreach $pid (sort {$a<=>$b} <*>) { next if $pid == $$.

$New{$pid}{ioch} = $pr_ioch. $filler) = unpack("iia8a8a8a8a8a8a8a8a8a8a8a8a8a8a48LLLLLLLLLLLLa40". $pr_ttydev. $pr_pctmem.next if $pid == 0 && $SCHED == 0. ### Read psinfo stats open(PSINFO. $pr_create. $pr_rtime. $New{$pid}{wtime} = timestruct2int($pr_wtime).$usage). $pr_ctime. $pr_sigs. $pr_egid. ### Read usage stats open(USAGE. $pr_vctx. $pr_term. $pr_pad1. $pr_projid. $pr_ltime. $pr_oublk. $pr_fname. $PID{$pid}{uid} = $pr_uid. $New{$pid}{oublk} = $pr_oublk. $New{$pid}{ictx} = $pr_ictx. $pr_mrcv. $pr_size. $pr_minf. $pr_ppid. $pr_wstat. $pr_majf. $pr_stoptime. $New{$pid}{sysc} = $pr_sysc."/proc/$pid/usage") || next. $New{$pid}{rssize} = $pr_rssize. # and a couple of my own. $pr_count. $pr_nzomb. close PSINFO. $pr_dmodel. $pr_start. $New{$pid}{ctxs} = $pr_vctx + $pr_ictx. ### Unpack psinfo values ($pr_flag. $New{$pid}{blks} = $pr_inblk + $pr_oublk. $pr_inblk. $New{$pid}{ltime} = timestruct2int($pr_ltime). $pr_addr. $pr_nlwp. $pr_poolid. $New{$pid}{inblk} = $pr_inblk. $pr_time. $pr_nswap. ### Save command name . $pr_zoneid. $filltime. $filler) = unpack("iiiiiiiiiiIiiiiSSa8a8a8Z16Z80iiIIaa3iiiiii". $pr_rssize. $pr_pctcpu. $pr_ioch. close USAGE."/proc/$pid/psinfo") || next. $pr_envp. $pr_slptime. $pr_argc. $New{$pid}{slptime} = timestruct2int($pr_slptime). $New{$pid}{stime} = timestruct2int($pr_stime). $New{$pid}{vctx} = $pr_vctx. $pr_tftime. $pr_wtime. ### Process psinfo values $PID{$pid}{pctcpu} = $pr_pctcpu / 0x8000. ### Process usage values $New{$pid}{utime} = timestruct2int($pr_utime).$psinfo). $pr_argv. ### Unpack usage values ($pr_lwpid.256). $pr_tstamp.$usage. $pr_gid. $pr_euid. $pr_utime. $PID{$pid}{pctmem} = $pr_pctmem / 0x8000. $pr_uid. read(PSINFO. $New{$pid}{majf} = $pr_majf.256). $pr_ictx. $pr_stime. $pr_sysc. read(USAGE. $pr_psargs. $pr_ttime. $pr_pid. $pr_taskid.$psinfo. $New{$pid}{nswap} = $pr_nswap. $New{$pid}{minf} = $pr_minf. $pr_msnd. $pr_kftime. $pr_dftime. $pr_sid. $New{$pid}{ttime} = timestruct2int($pr_ttime). $pr_pgid. next if $TARGET_PID > -1 && $pid != $TARGET_PID. $New{$pid}{size} = $pr_size.

while ($line = <DTRACE>) { chomp($line).$pid. # sub GetDTraceStat { my ($line.$rest) = split(' '. $PID{$pid}{netrw} += $size. } } } # GetDTraceStat . next if $TARGET_PID > -1 && $pid != $TARGET_PID.$rest). unless (defined $Comm{$pid}) { $Comm{$pid} = $name. unless (defined $Comm{$pid}) { $Comm{$pid} = $name.$size.$name) = split(' '.2).$size.$uid.$delta. .$line. ### Remember old value foreach $pid (keys %New) { # save old values. $PID{$pid}{uid} = $uid. foreach $key (keys %{$New{$pid}}) { $Old{$pid}{$key} = $New{$pid}{$key}.$name) = split(' '.read detals from a DTrace connection until a heartbeat # is read (happens every second).$pid. } ### Turn incrementals into values foreach $pid (keys %New) { # save PID values. } } undef %Old. $PID{$pid}{dtime} += $delta.$size. } ### Network traffic if ($cmd eq "N") { ($uid. ### Heartbeat if ($cmd eq "T") { $TIME_END = $rest.$delta).$rest.$cmd. ### Start $TIME_BEGIN = $rest if $cmd eq "B".$pid. $PID{$pid}{uid} = $uid.$Comm{$pid} = $pr_fname.$Old{$pid}{$key}. next if $TARGET_PID > -1 && $pid != $TARGET_PID.$name. } } ### Disk traffic if ($cmd eq "D") { ($uid. ($cmd. last. foreach $key (keys %{$New{$pid}}) { $PID{$pid}{$key} = $New{$pid}{$key} .$rest).

$factorcpu = 100.$cpu. $mem = $PID{$pid}{pctmem} * $factormem.$mem.2f %6. $factormem = 100. } # Print output printf("%5s %6.33)).$mem.02)) { next."%Disk".$disk. $PID{$pid}{mem} = $mem.$net."%Net". $net = $PID{$pid}{net}.$factormem. ### Process %PID foreach $pid (keys(%PID)) { $cpu = $PID{$pid}{pctcpu} * $factorcpu. my ($pid.$factordisk.print a report on utilisation. $PID{$pid}{net} = $net. ### Print header printf("%5s %6s %6s %6s %6s %s\n". $PID{$pid}{cpu} = $cpu.$disk. my ($factorcpu. # Skip zero lines if needed if ($ZERO && ($all < 0. $all = $PID{$pid}{all}.} } } } # ProcessPID .$net.2f %6.$pid. . $disk = $PID{$pid}{disk}. $factordisk = 100 / $sample.trunc($Comm{$pid}. "%CPU"."%Mem"."PID".2f %6. $cpu.$net. $disk = $PID{$pid}{dtime} * $factordisk.$factornet). ### Print report foreach $pid (&SortPID("$sort")) { # Fetch utilisations $cpu = $PID{$pid}{cpu}. # This calculates values such as sumpct for sorting. $PID{$pid}{disk} = $disk. ### Factors for %util conversions $sample = $TIME_END .pre process %PID before printing. } } # PrintUtil . $PID{$pid}{all} = $cpu + $mem + $disk + $net.$sample)."COMM").$all).$TIME_BEGIN || 1.$mem. $mem = $PID{$pid}{mem}. $net = $PID{$pid}{netrw} * $factornet. # sub ProcessPID { my ($pid.2f %s\n". # sub PrintUtil { my $sort = shift || "all".$cpu. $factornet = 800 / ($NIC_SPEED * ($sample / 1_000_000_000)).$disk. my $top = $TOP.

"%Mem". my ($pid. } print "\n" if $MULTI.$all).$pid. my $top = $TOP. # sub PrintExtra { my $sort = shift || "all".trunc($Comm{$pid}. "CHAR-kb". last if --$top == 0. $mem = $PID{$pid}{mem}.last if --$top == 0. } # PrintIO . $mem = $PID{$pid}{mem}.4f %s\n". ### Print header printf("%5s %6s %6s %6s %6s %8s %8s %9s %s\n". inblk.02)) { next. oublk. ### Print report foreach $pid (&SortPID("$sort")) { # Fetch utilisations $cpu = $PID{$pid}{cpu}. $disk = $PID{$pid}{disk}. "%CPU"."COMM")."%Mem". # sub PrintIO { my $sort = shift || "blks". # Skip zero lines if needed ."%Disk". my $top = $TOP. $net = $PID{$pid}{net}."%Disk".$disk.$cpu.$net."%Net". # Skip zero lines if needed if ($ZERO && ($all < 0."PID".$all).$disk. majf.$cpu."COMM").4f %8. $net = $PID{$pid}{net}. $all = $PID{$pid}{all}.$mem."%Net". ### Print report foreach $pid (&SortPID("$sort")) { # Fetch utilisations $cpu = $PID{$pid}{cpu}.4f %8.4f %8. my ($pid.$disk. $disk = $PID{$pid}{disk}."INBLK". $cpu. ioch.33)). } # Print output printf("%5s %8.$mem.$net. } # PrintExtra .$net.print a report with I/O statistics: minf. with extra decimal places."OUBLK". $all = $PID{$pid}{all}. } print "\n" if $MULTI. "%CPU"."PID". ### Print header printf("%5s %8s %8s %8s %8s %s\n".print a report on utilisation.$mem.

$cpu. my ($pid. ictx and sys calls. } print "\n" if $MULTI."COMM").$net.33)). "%CPU". my ($pid. } # Print output printf("%5s %6.if ($ZERO && ($all < 0. trunc($Comm{$pid}. trunc($Comm{$pid}.2f %6.$PID{$pid}{inblk}.2f %8d %8d %9.print a report including usr.2f %8d %8d %8d %s\n". # sub PrintCtx { my $sort = shift || "ctxs". "WAIT"."%Disk".$mem."VCTX".$PID{$pid}{utime}. # sub PrintTime { my $sort = shift || "cpu"."PID". $pid.$all).$cpu. $all = $PID{$pid}{all}.2f %6. $disk = $PID{$pid}{disk}. my $top = $TOP.$all)."ICTX". ### Print report foreach $pid (&SortPID("$sort")) { # Fetch utilisations $cpu = $PID{$pid}{cpu}. $net = $PID{$pid}{net}."%Net".$mem."%Mem"."SYS".$disk. "SYSC".33)). $mem = $PID{$pid}{mem}.2f %6.$mem.$mem. "%CPU".$net."%Mem".0f %s\n". $PID{$pid}{oublk}.$disk.$net.2f %6. $pid. } # Print output printf("%5s %6.$net. } # PrintTime . my $top = $TOP. last if --$top == 0. $PID{$pid}{stime}. ### Print header printf("%5s %6s %6s %6s %6s %8s %8s %8s %s\n".$cpu. ### Print header printf("%5s %6s %6s %6s %6s %8s %8s %9s %s\n". last if --$top == 0.2f %6."USR".print a report on context switches: vctx.$PID{$pid}{ioch}/1024.02)) { next.$cpu. } # PrintCtx .$disk."PID"."COMM").2f %6. } print "\n" if $MULTI."%Disk"."%Net". sys and wait times.02)) { next. # Skip zero lines if needed if ($ZERO && ($all < 0.$PID{$pid}{wtime}.$disk. ### Print report .

$all = $PID{$pid}{all}. } else { return substr($string.$mem.Convert a timestruct value (64 bits) into an integer # of seconds.$cpu. if ($WIDE) { return $string. my $length = shift. $mem = $PID{$pid}{mem}.foreach $pid (&SortPID("$sort")) { # Fetch utilisations $cpu = $PID{$pid}{cpu}.$PID{$pid}{sysc}.$timestruct). } else { return sort {$PID{$b}{$sort} <=> $PID{$a}{$sort}} (keys %PID).2f %6.subroutine for signal management.sorts the PID hash by the key given as arg1. ### Sort numerically if ($sort eq "pid") { return sort {$a <=> $b} (keys %PID). trunc($Comm{$pid}.02)) { next.0.$disk. } # Print output printf("%5s %6. } # trunc . return $time.$PID{$pid}{vctx}.$length). } print "\n" if $MULTI. $pid.$net.Returns a truncated string if required.2f %6. # sub trunc { my $string = shift. # sub timestruct2int { my $timestruct = shift. $PID{$pid}{ictx}.$nsecs) = unpack("LL". my ($secs. } # SortPID . } } # Cleanup . . returning a sorted # array of PIDs.33)). # sub SortPID { my $sort = shift. # Skip zero lines if needed if ($ZERO && ($all < 0. $disk = $PID{$pid}{disk}. $net = $PID{$pid}{net}.2f %8d %8d %9d %s\n". last if --$top == 0.2f %6. my $time = $secs + $nsecs * 10**-9. } } # timestruct2int .

print top number of lines only eg. inode. } # # --. ** */ #pragma D option quiet . command.DTrace --# __DATA__ /usr/sbin/dtrace -n ' /* ** The following is a trimmed version of two seperate DTrace scripts: ** ** socketsnoop. Written in DTrace (Solaris 10 build 63). # # # # # 2 second samples (first is historical) 5 x 10 second samples 5 x 10 second samples. every 5 secs END exit. every 5 secs # 22 lines.snoop TCP network socket traffic by process.d . # sub Usage { print STDERR <<END. ** This is intended to identify the process responsible ** for network traffic. prustat ver 0. sort by cpu. all reports every 10 seconds # 22 lines. ** Written in DTrace (Solaris 10 build 63). sort by network. every 5 secs # 22 lines. } # Usage . etc.. exit(0)..A program to print I/O events as they happen. PID. ** ** iosnoop.d . demo release USAGE: prustat [-cehinuwxz] [-p PID] [-s sort] [-t top] [interval] [count] prustat prustat prustat prustat prustat prustat prustat prustat prustat prustat prustat -i -u -x -c -w -z -e -p PID -s sort -t lines # # # # # # # # # # # prustat prustat prustat prustat prustat prustat prustat prustat prustat 2 10 5 -t 8 10 5 -ct 20 5 -iuxct 5 10 -ct 22 -s cpu 5 -ct 22 -s mem 5 -ct 22 -s net 5 -ct 22 -s disk 5 \%Utilisation + I/O stats + USR/SYS times + Context Switchs Clear screen Wide output Skip zero lines Extra precision this PID only sort on pid|cpu|mem|disk|net|utime|vctx|.print usage message and exit. sort by mem. top 8 lines only 20 lines with screen refresh each 5 seconds multi output.# sub Cleanup { close(DTRACE).50. with useful ** details such as UID. sort by disk. every 5 secs # 22 lines.

this->blk] = pid. start_pid[this->dev.this->blk]. this->delta = timestamp . this->suid = start_uid[this->dev.this->blk]. last = timestamp. /* memory cleanup */ start_uid[this->dev. start_uid[this->dev.last. /* last is used as a timestamp to the disk request./* ** --.this->blk]. } profile:::tick-1sec { /* heartbeat */ printf("T %d\n".timestamp).timestamp). */ last = timestamp. this->blk = args[0]->b_blkno. } /* ** Print event details */ io:::done { . This is needed to avoid over counting disk times due to disk buffers (queues). start_pid[this->dev.TIMESTAMPS --*/ dtrace:::BEGIN { printf("B %d\n". this->blk = args[0]->b_blkno.this->blk] = 0. last = timestamp. } /* ** --. this->scomm = start_comm[this->dev. } /* ** Process completion */ io:::done { /* fetch entry values */ this->dev = args[0]->b_edev.this->blk] = curpsinfo->pr_euid. this->spid = start_pid[this->dev.this->blk] = 0. start_comm[this->dev.this->blk] = (char *)curpsinfo->pr_fname.this->blk] = 0.DISK ---*/ /* ** Store entry details */ io:::start { this->dev = args[0]->b_edev. start_comm[this->dev. however remains a minor simplification. OR. to the last disk completion.

h). self->ok = 0. self->ok = (int)this->sonode->so_type == 2 ? 1 : 0. */ self->uiop = (struct uio *) arg2.this->delta. self->ok = 1. self->size. self->comm = (char *)curpsinfo->pr_fname. self->pid = pid. self->comm = 0. /* The following ensures the type is AF_INET (sys/socket.args[0]->b_bcount. self->residual = 0. /* We track the read request (man uio). } /* ** Store Read Values */ fbt:sockfs:sotpi_recvmsg:entry { self->uid = curpsinfo->pr_euid.self->uiop->uio_resid." : stringof(this->scomm)).self->pid. this->scomm == 0 ? ". self->pid = 0. self->residual = self->uiop->uio_resid.printf("D %d %d %d %d %s\n". self->uiop = 0. } . } fbt:sockfs:sotpi_recvmsg:return /arg0 != 0 && self->ok/ { /* calculate successful read size */ self->size = self->residual . self->comm = (char *)curpsinfo->pr_fname. self->pid = pid.self->uid. */ this->sonode = (struct sonode *)arg0.stringof(self->comm)). self->uid = 0.NETWORK ---*/ /* ** Store Write Values */ fbt:ip:tcp_output:entry { self->uid = curpsinfo->pr_euid. } /* ** --. fbt:sockfs:sotpi_recvmsg:return /self->ok/ { printf("N %d %d %d %s\n". } /* ** Print output */ fbt:ip:tcp_output:entry.this->spid. self->size = 0. this->suid. self->size = msgdsize(args[1]).

' .