/*
This file is part of demos for "Mutex Internals"
presentation at Hotsos Symposium 2012
Andrey S. Nikolaev (Andrey.Nikolaev@rdtex.ru)
http://AndreyNikolaev.wordpress.com
Compute the mutex statistics
For Oracle versions 11.2
usage:
sqlplus /nolog @mutex_stats mutex_identifier=<...>
or
sqlplus /nolog @mutex_stats mutex_address=0x<...>
*/
connect / as sysdba
set verify off
set echo off
SET SERVEROUTPUT ON
set timing on
declare
arg varchar2(1000);
n PLS_INTEGER;
i NUMBER;
j number;
idn number;
Samples NUMBER;
SampleFreq NUMBER;
wordsize number;
rho_s number;
rho_x number;
Error_ varchar2(2000);
eta number;
muvalue varchar2(20);
dgets number;
dsleeps number;
lambda number;
omega number;
S number;
kappa number;
zeta number;
K number;
ssleep number;
sigma number;
omega_prime number;
dmisses number;
rho number;
params varchar2(2000);
lcname varchar2(1000);
Nw number;
/* mutex statistics */
cursor mustat(muindx number) is
select decode(dbms_utility.get_endianness,1,p2,p1) gets,decode(dbms_utility.get_endianness(),1,p1,p2) sleeps
from (select FLOOR(val/POWER(2,4*wordsize)) p2, MOD (val,POWER(2,4*wordsize)) p1 from
(select to_number(ksmmmval,'XXXXXXXXXXXXXXXX') val from x$ksmmem where indx=muindx)); /* next after mutex index */
cursor Hold(muindx number) is select rawtohex(ksmmmval) from x$ksmmem where indx=muindx;
cursor Wait(idn_ number) is select count(*) from v$session_wait where p1text='idn' and p1=idn_ and state='WAITING';
/* mutexes: */
TYPE mutex IS RECORD (addr RAW(8), mutex_type varchar2(30), indx number,
U number, Ux number,dtime number,
mus_start mustat%rowtype, mus_end mustat%rowtype);
TYPE mutex_tab is table of mutex index by PLS_INTEGER; /* table for all mutexes associated with this identifier */
mu mutex_tab;
/* Library cache objects statistics */
cursor ls_(idn_ in number) is select case when (kglhdadr = kglhdpar) then 'Parent' else 'Child '||kglobt09 end par,
kglhdadr addr,kglobtyd type,kglnaown owner,kglnaobj name,kglobt23 locks,kglobt24 pins,kglhdexc executions,kglhdnsp namespace
from x$kglob where kglnahsh=idn_
order by name,decode(kglobt09,65535,-1,kglobt09);
type lstat_ IS RECORD(addr RAW(8), par varchar2(15),name varchar2(1000),locks number,pins number, executions number,namespace number);
type lstat__ is table of lstat_ index by varchar2(16);
lstat lstat__;
BEGIN
arg:='&1';
SampleFreq := 1 / 10; -- Hz
Samples := 300;
SELECT DECODE (INSTR (banner, '64'), 0, '4', '8') ws into wordsize FROM v$version WHERE ROWNUM = 1;
Nw:=0;
/* CPU count */
select value into eta from v$parameter where name = 'cpu_count';
eta:= eta/(eta-1); /* correction coefficient */
/* 1. Argument is mutex identifier. There may be several mutexes with the same idn. */
if regexp_like(arg,'^(mutex_)?id(n|entifier)=[[:digit:]]+','i') then
/* obtain mutex addresses from 10 minute history of recent waits */
n:=0;
idn:=to_number(substr(arg,regexp_instr(arg,'^(mutex_)?id(n|entifier)=',1,1,1,'i')));
FOR lw in (select distinct mutex_addr,mutex_type
from x$mutex_sleep_history
where mutex_identifier= idn
and sleep_timestamp > systimestamp - interval '10' minute)
LOOP
n:=n+1;
mu(n).addr := lw.mutex_addr;
mu(n).mutex_type:=lw.mutex_type;
mu(n).indx:=NULL;
END LOOP;
if n = 0 then raise_application_error(-20001,'Can not find mutex with idn: '||idn||' in x$mutex_sleep_history');
end if;
/* 2. Argument is mutex address. */
elsif regexp_like(arg,'^(mutex_)?addr(ess)?=0x[[:xdigit:]]+','i') then
n:=1;
mu(n).addr := HEXTORAW (lpad(upper(substr(arg,regexp_instr(arg,'^(mutex_)?addr(ess)?=0x',1,1,1,'i'))),16,'0'));
if mu(n).addr = '00' then
raise_application_error(-20001,'Invalid mutex address: '||arg);
end if;
idn:=null;
mu(n).mutex_type:=NULL;
mu(n).indx:=NULL;
/* find mutex identifier from x$mutex_sleep_history */
for lw in (select mutex_identifier, mutex_type
from x$mutex_sleep_history
where mutex_addr=mu(1).addr)
loop
idn:= lw.mutex_identifier;
mu(n).mutex_type:=lw.mutex_type;
end loop;
else
raise_application_error(-20003,'Usage: sqlplus /nolog @mutex_stat (mutex_identifier=... | mutex_address=0x...)');
end if;
/* Compute indx in x$ksmmem for mutex address(es) */
FOR j IN 1 .. n
loop
for sga in (select indx from x$ksmmem where addr=mu(j).addr)
loop
mu(j).indx:=sga.indx;
end loop;
if mu(j).indx is null then
raise_application_error(-20002,'No such address in SGA: 0x'||rawtohex(mu(j).addr));
end if;
mu(j).U:=0;
mu(j).Ux:=0;
/* library cache statistics at beginning */
if idn > 0 then
for ls in ls_(idn)
loop
params:=rawtohex(ls.addr);
lstat(params).addr:=params;
lstat(params).locks:=ls.locks;
lstat(params).pins:=ls.pins;
lstat(params).executions:=ls.executions;
lstat(params).namespace:=ls.namespace;
end loop;
end if;
/* Mutex statistics at start */
mu(j).dtime := DBMS_UTILITY.GET_TIME();
OPEN mustat(mu(j).indx+1);
FETCH mustat into mu(j).mus_start;
CLOSE mustat;
end loop;
/* Sampling */
FOR i IN 1 .. Samples
LOOP
DBMS_LOCK.sleep (SampleFreq);
/* Average number of waiting sessions */
OPEN Wait(idn);
FETCH Wait into muvalue;
CLOSE Wait;
Nw:=Nw+muvalue;
/* for all mutexes with this indx: */
FOR j IN 1 .. n
loop
OPEN Hold(mu(j).indx);
FETCH Hold into muvalue;
CLOSE Hold;
if muvalue <> '00' then
mu(j).U:=mu(j).U+1;
if length(ltrim(muvalue,'0')) > wordsize then /* upper mutex bytes is not zero */
mu(j).Ux:=mu(j).Ux+1;
end if;
end if;
end loop;
END LOOP;
/* End mutex statistics */
FOR j IN 1 .. n
loop
OPEN mustat(mu(j).indx+1);
FETCH mustat into mu(j).mus_end;
CLOSE mustat;
mu(j).dtime:=(DBMS_UTILITY.GET_TIME()-mu(j).dtime)*0.01; /* delta time in seconds */
end loop;
/* Compute derived statistics */
FOR j IN 1 .. n
loop
Error_:='';
rho_s:=(mu(j).U-mu(j).Ux)/Samples;
rho_x:=mu(j).Ux/Samples;
rho:=mu(j).U/Samples;
dgets := mu(j).mus_end.gets - mu(j).mus_start.gets;
dsleeps:= mu(j).mus_end.sleeps - mu(j).mus_start.sleeps;
lambda:= dgets/mu(j).dtime;
omega := dsleeps/mu(j).dtime;
if(dgets>0) then
S := rho_x/lambda ; -- mutex holding time in usecs
else
Error_ := Error_||' Delta Gets='||dgets; /* there was no mutex gets */
end if;
if(lambda*rho_x!=0) then
kappa := omega/(lambda*rho_x); -- sleep ratio
else
Error_ := Error_||' rho_x=0, lambda= '||trunc(lambda)||' Hz'; /* we didn't saw mutex in X mode */
kappa :=null;
end if;
zeta := lambda*rho_x; -- miss rate
K := kappa/(1+kappa*rho_x); -- spin efficiency
sigma:=1-K;
if(nvl(kappa,0)!=0) then
ssleep := (sigma+kappa-1)/kappa ; -- secondary sleep ratio
else
Error_ := Error_||' kappa=0 ';
ssleep :=null;
end if;
omega_prime:=zeta*K ; -- waits estimation from mutex stats
if(length(Error_)>0 ) then
DBMS_OUTPUT.put_LINE (' Error: '||Error_);
else
DBMS_OUTPUT.put_LINE (chr(10)||'--------------------------------------------');
DBMS_OUTPUT.put_LINE ('Statistics for "'||mu(j).mutex_type||'" mutex');
DBMS_OUTPUT.put_LINE ('idn: '||idn||' address 0x'||mu(j).addr);
DBMS_OUTPUT.put_LINE ('Interval: '||to_char(mu(j).dtime,'999.9')||' s, gets: ' ||dgets||', sleeps:'||dsleeps||chr(10));
DBMS_OUTPUT.put_LINE ('Requests rate: lambda=' || to_char(lambda,'999999999.9')||' Hz');
DBMS_OUTPUT.put_LINE ('Sleeps rate: omega= ' || to_char(omega,'999999999.9')||' Hz');
DBMS_OUTPUT.put_LINE ('Utilization: rho= ' || to_char(rho,'9.999999'));
DBMS_OUTPUT.put_LINE ('Exclusive Utilization: rho_x=' || to_char(rho_x,'9.999999'));
DBMS_OUTPUT.put_LINE ('Shared Utilization: rho_s=' || to_char(rho_s,'9.999999'));
DBMS_OUTPUT.put_LINE ('Avg. holding time: S=' || to_char(S*1000000,'9999999.99')||' us');
DBMS_OUTPUT.put_LINE ('Service rate: mu= ' || to_char(1/S,'9999999999.9')||' Hz');
DBMS_OUTPUT.put_LINE ('Spin inefficiency: k= ' || to_char(K,'9.999999'));
DBMS_OUTPUT.put_LINE (chr(10)||'Secondary statistics:');
DBMS_OUTPUT.put_LINE ('Slps /Miss: kappa=' || to_char(kappa,'9.999999'));
DBMS_OUTPUT.put_LINE ('Spin_gets/miss: sigma=' || to_char(sigma,'9.999999'));
DBMS_OUTPUT.put_LINE ('correction coeff. eta=' || to_char(eta,'9.9'));
DBMS_OUTPUT.put_LINE ('Secondary sleeps ratio ' || to_char(ssleep,'9.999'));
end if;
end loop;
DBMS_OUTPUT.put_LINE (chr(10)||'--------------------------------------------');
DBMS_OUTPUT.put_LINE ('Avg. number of sessions waiting: ' || to_char(Nw/Samples,'9999.99'));
/* */
if idn > 0 then
lcname:=' ';
DBMS_OUTPUT.put_LINE (chr(10)||'Library cache object related to mutex idn ' || idn||' :'||chr(10));
for ls in ls_(idn)
loop
if ls.name != lcname then
if ls.type='CURSOR' then
DBMS_OUTPUT.put_LINE (ls.type||': '||ls.name);
else
DBMS_OUTPUT.put_LINE (ls.type||': '||ls.owner||'.'||ls.name);
end if;
DBMS_OUTPUT.put_LINE (chr(10)||'ADDR: TYPE PIN/s: LOCK/s: EXEC/s: Namespc' );
DBMS_OUTPUT.put_LINE ('-------------------------------------------------------------------');
lcname:=ls.name;
end if;
begin
params:=rawtohex(ls.addr);
DBMS_OUTPUT.put_LINE (rpad(ls.addr,16)||' '||rpad(rtrim(ls.par),10)||
to_char((ls.pins -lstat(params).pins )/mu(1).dtime,'9999999')||' '||
to_char((ls.locks-lstat(params).locks)/mu(1).dtime,'9999999')||' '||
to_char((ls.executions-lstat(params).executions)/mu(1).dtime,'9999999')||
' '||to_char(ls.namespace,'9999'));
exception when NO_DATA_FOUND then
null;
end;
end loop;
end if;
/* mutex parameters */
params:='';
for Param in (select ksppinm,ksppstvl from x$ksppi x join x$ksppcv using (indx )
where ksppinm like '%mutex%' or ksppinm like '%wait_yield%' order by ksppinm)
loop
params:=params||Param.ksppinm||'='||Param.ksppstvl||' ';
end loop;
DBMS_OUTPUT.put_LINE (chr(10) ||'Mutex related parameters:'||chr(10) || params);
END;
/
mutex_stats.sql
Leave a Comment »
No comments yet.
RSS feed for comments on this post. TrackBack URI