#!/bin/ksh -p # util-old-new - Show CPU utilisation as seen by S10 & pre-S10 acctng # # @(#)util-old-new 1.3 08/02/22 Tim.Cook@sun.com # with help from Brendan.Gregg@sun.com # # This DTrace script uses the sched provider to trace how much time is # spent on-cpu by non-idle threads, which should closely match the # microstate accounting of S10+. # # It also measures the amount that lbolt64 is incremented while non-idle # threads are on-cpu, which should closely match the clock()-based # accounting of S9 and earlier, because lbolt64 is updated in clock(). # # Interrupts that do not pin another thread are also tracked - this # utilisation was not captured by Solaris 8. # # The output is normalised to per-thousand, per-CPU values (i.e. 10 times # a percent CPU metric). PATH=/usr/sbin:/usr/bin:/bin ; export PATH case $#,$1 in 0, ) interval=10 ;; 1,[0-9]* ) interval=$1 ;; * ) echo "usage: $0 [interval]" >&2 exit 1 ;; esac /usr/sbin/dtrace -C -q -s /dev/stdin $interval << 'EOT' uint64_t start_n; int64_t period_t; BEGIN /($1 * `ncpus_online) % 10 != 0/ { /* * Otherwise when we normalize ticks/1000 we could be off */ printf("Sorry, NCPUs (%d) x INTERVAL (%d) needs to be a multiple of 10", `ncpus_online, $1); exit(1); } BEGIN { start_n = timestamp; timer = $1; header = timer; /* * ticks/1000 normalisation factor */ norm_t = $1 * `ncpus_online / 10; printf("NCPUs = %d\n", `ncpus_online); } /* Any thread other than fsflush */ sched:::on-cpu /curthread->t_pri != -1 && pid != 3/ { on_n[cpu] = timestamp; on_tick[cpu] = `lbolt64; } /* * Special case: fsflush, which can be on the CPU for multiple seconds, * without firing remain-cpu. */ sched:::on-cpu /pid == 3/ /* fsflush */ { on_n_fsf = timestamp; on_n[cpu] = on_n_fsf; on_tick_fsf = `lbolt64; } /* Check each second if fsflush is still running & update totals */ profile:::tick-1s /on_n_fsf/ { this->used_n = timestamp - on_n_fsf; on_n_fsf = timestamp; this->used_tick = `lbolt64 - on_tick_fsf; on_tick_fsf = `lbolt64; @util = sum(this->used_n); @s8_util = sum(this->used_tick); @s9_util = sum(this->used_tick); } /* fsflush is done */ sched:::off-cpu /pid == 3/ { this->used_n = timestamp - on_n_fsf; this->used_tick = `lbolt64 - on_tick_fsf; @util = sum(this->used_n); @s8_util = sum(this->used_tick); @s9_util = sum(this->used_tick); on_n[cpu] = 0; on_tick[cpu] = 0; on_n_fsf = 0; on_tick_fsf = 0; } /* Catch interrupts that hit idle CPUs */ sdt:::interrupt-start /on_n[cpu] == 0/ { /* An interrupt that hit an idle CPU */ int_n[cpu] = timestamp; int_tick[cpu] = `lbolt64; } sdt:::interrupt-complete /int_n[cpu]/ { this->int_delta = timestamp - int_n[cpu]; @util = sum(this->int_delta); @s9_util = sum(`lbolt64 - int_tick[cpu]); int_n[cpu] = 0; int_tick[cpu] = 0; } /* Updating totals when remain-cpu fires improves granularity */ sched:::remain-cpu /on_n[cpu]/ { this->used_n = timestamp - on_n[cpu]; this->used_tick = `lbolt64 - on_tick[cpu]; on_n[cpu] = timestamp; on_tick[cpu] = `lbolt64; @util = sum(this->used_n); @s8_util = sum(this->used_tick); @s9_util = sum(this->used_tick); } sched:::off-cpu /on_n[cpu] && pid != 3/ { this->used_n = timestamp - on_n[cpu]; this->used_tick = `lbolt64 - on_tick[cpu]; /* @max_n = max(this->used_n); */ @util = sum(this->used_n); @s8_util = sum(this->used_tick); @s9_util = sum(this->used_tick); /* * Un-comment this if you want to see a distribution of * nanoseconds to ticks */ /* @ns_distrib[this->used_tick] = quantize(this->used_n); */ on_n[cpu] = 0; on_tick[cpu] = 0; } /* Print a header for every 20 lines of output */ profile:::tick-1s /--header == 0/ { /* Print a header */ printf("Date-time s8-tk/1000 s9-tk/1000 ns/1000\n"); header = $1 * 20; } profile:::tick-1s /--timer == 0/ { timer = $1; lines--; this->period_n = timestamp - start_n; start_n += this->period_n; normalize(@util, this->period_n * `ncpus_online / 1000); normalize(@s8_util, norm_t); normalize(@s9_util, norm_t); printf("%Y ", walltimestamp); #ifdef __SunOS_5_10 printa("%@4lu ", @s8_util); printa("%@4lu ", @s9_util); printa("%@4lu\n", @util); #else printa("%@4ld %@04ld %@04ld\n", @s8_util, @s9_util, @util); #endif trunc(@util); trunc(@s8_util); trunc(@s9_util); } EOT