(A previous Blog: dbms_aq.dequeue - latch: row cache objects on AIX talked about dbms_aq.dequeue and latch: row cache objects)
As a concrete test example, appended code contains two different implementations of PL/SQL - Java interface when calling XML Pull Parser (XmlPullParser).
- Case_1: for each TAG and text, make one java call.
- Case_2: make one single java call for whole XML Document.
All tests are done on AIX Power7 System with Entitled Capacity 4, SMT=4 and Oracle 11.2.0.3.0.
It is also reproducible on Solaris Operating System (x86-64) with 16 virtual processors (2 8-Cores physical processors).
It is also reproducible on Solaris Operating System (x86-64) with 16 virtual processors (2 8-Cores physical processors).
Case_1 32 Jobs
At first, run Case_1 for 10 minutes with 32 Jobs:
exec xpp_test.run_job(p_case => 1, p_job_cnt => 32, p_dur_seconds => 600);
and look the top 5 events in AWR report:
Top 5 Timed Foreground Events
Event | Waits | Time(s) | Avg wait (ms) | % DB time | Wait Class |
---|---|---|---|---|---|
DB CPU | 2,410 | 6.70 | |||
latch: row cache objects | 7,026 | 1,301 | 185 | 3.62 | Concurrency |
library cache: mutex X | 3,756 | 111 | 30 | 0.31 | Concurrency |
log file sync | 32 | 1 | 41 | 0.00 | Commit |
control file sequential read | 3,700 | 1 | 0 | 0.00 | System I/O |
we can see a noticeable "latch: row cache objects" with average wait of 185 ms.
During the job running, pick the hex address of 'latch: row cache objects' by:
SQL> select p1raw from v$session v where p2=280 or event = 'latch: row cache objects';
0X7000000B412F9F0
To look Oracle internal data structure, dump 16 bytes starting from this address by:
SQL> oradebug peek 0X7000000B412F9F0 16
[7000000B412F9F0, 7000000B412FA10) = 00000000 00000026 2ED50834 01180000
where
00000026 is Oracle PID (38 in hex) which is currently holding the latch.
2ED50834 is v$latch.gets (785713204 in hex) where name='row cache objects'.
0118 is v$latch.latch# (280 in hex).
If dumping address further, you can also find v$latch.misses, sleeps and other columns.
Case_1 16 Jobs
If reducing Jobs to 16,
exec xpp_test.run_job(p_case => 1, p_job_cnt => 16, p_dur_seconds => 600);
AWR shows:
Top 5 Timed Foreground Events
Event | Waits | Time(s) | Avg wait (ms) | % DB time | Wait Class |
---|---|---|---|---|---|
DB CPU | 2,385 | 14.19 | |||
library cache: mutex X | 9,989 | 1 | 0 | 0.01 | Concurrency |
control file sequential read | 3,588 | 1 | 0 | 0.00 | System I/O |
db file sequential read | 839 | 0 | 0 | 0.00 | User I/O |
latch: row cache objects | 27 | 0 | 2 | 0.00 | Concurrency |
Case_2 32 Jobs
Then repeating the above two calls with Case_2:
exec xpp_test.run_job(p_case => 2, p_job_cnt => 32, p_dur_seconds => 600);
Top 5 Timed Foreground Events
Event | Waits | Time(s) | Avg wait (ms) | % DB time | Wait Class |
---|---|---|---|---|---|
DB CPU | 2,401 | 6.66 | |||
log file sync | 40 | 2 | 39 | 0.00 | Commit |
control file sequential read | 3,700 | 1 | 0 | 0.00 | System I/O |
cursor: pin S wait on X | 2 | 0 | 130 | 0.00 | Concurrency |
SQL*Net break/reset to client | 54 | 0 | 4 | 0.00 | Application |
Case_2 16 Jobs
exec xpp_test.run_job(p_case => 2, p_job_cnt => 16, p_dur_seconds => 600);
Top 5 Timed Foreground Events
Event | Waits | Time(s) | Avg wait (ms) | % DB time | Wait Class |
---|---|---|---|---|---|
DB CPU | 2,416 | 11.12 | |||
log file sync | 88 | 5 | 52 | 0.02 | Commit |
latch: shared pool | 1 | 1 | 978 | 0.00 | Concurrency |
control file sequential read | 3,588 | 1 | 0 | 0.00 | System I/O |
library cache: mutex X | 169 | 1 | 6 | 0.00 | Concurrency |
We can hardly see any "latch: row cache objects" in other three AWR reports.
TestCode
create or replace type xpp_array_obj as object (
evt_type number(12)
,name varchar2(32767)
,namespc varchar2(4000)
,attr_cnt number(12)
,text varchar2(32767)
);
/
create or replace type xpp_array_tab as table of xpp_array_obj;
/
drop table test_stats;
create table test_stats (ts timestamp, case number, job_cnt number, dur number, run_cnt number, java_cnt number, java_nano number);
drop table rc_latch_stats;
create table rc_latch_stats as
select timestamp'2013-11-22 10:20:30' ts, 'start' step, 0 case, 0 job_cnt, v.*
from v$latch v where 0=1 and name = 'row cache objects';
drop java source "XmlPullParserJava";
create or replace and resolve java source named "XmlPullParserJava" as
import java.util.LinkedList;
import java.util.Vector;
import java.sql.Connection;
import java.sql.Clob;
import oracle.jdbc.driver.OracleDriver;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
import org.xmlpull.mxp1.MXParser;
import org.xmlpull.v1.XmlPullParser;
public class XmlPullParserJava {
private static XmlPullParser XPP = new MXParser();
public static void setInput(Clob inputClob) {
try {
XPP.setInput(inputClob.getCharacterStream());
} catch (Exception t) {
System.out.println("\n Message: " + t.getMessage() + "\n Cause: " + t.getCause());
}
}
public static int next(String[] name, String[] namespace, int[] attributeCount, String[] text, long[] elapsed) {
try {
long startTime = System.nanoTime();
int next = XPP.next();
name[0] = XPP.getName();
namespace[0] = XPP.getNamespace();
attributeCount[0] = XPP.getAttributeCount();
text[0] = XPP.getText();
elapsed[0] = System.nanoTime() - startTime;
return next;
} catch (Throwable t) {
System.out.println("\n Message: " + t.getMessage() + "\n Cause: " + t.getCause());
return -1;
}
}
public static void nextAll(ARRAY retAllArray[], long[] elapsed) {
try {
Connection conn = new OracleDriver().defaultConnection();
ArrayDescriptor aDescr = ArrayDescriptor.createDescriptor("XPP_ARRAY_TAB", conn);
StructDescriptor sDescr = StructDescriptor.createDescriptor("XPP_ARRAY_OBJ", conn);
String [] lineContent = new String[5];
STRUCT lineObj = null;
Vector retAll = new Vector();
long startTime = System.nanoTime();
String name;
String nameSpace;
int attributeCount;
String text;
int eventType = XPP.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
lineContent[0] = String.valueOf(eventType);
lineContent[1] = XPP.getName();
lineContent[2] = XPP.getNamespace();
lineContent[3] = String.valueOf(XPP.getAttributeCount());
lineContent[4] = XPP.getText();
lineObj = new STRUCT(sDescr, conn, lineContent);
retAll.add(lineObj);
eventType = XPP.next();
}
elapsed[0] = System.nanoTime() - startTime;
retAllArray[0] = new ARRAY(aDescr, conn, retAll.toArray());
} catch (Throwable t) {
System.out.println("\n Message: " + t.getMessage() + "\n Cause: " + t.getCause());
}
}
}
/
create or replace package k.xpp_test as
type xpp_rec is record (
evt_type pls_integer
,name varchar2(32767)
,namespc varchar2(4000)
,attr_cnt pls_integer := -1
,text varchar2(32767)
,elapsed pls_integer
);
v_xpp_rec xpp_rec;
v_xml_doc varchar2(32767);
v_java_call_nano number := 0;
v_java_call_cnt number := 0;
---------------------------------------------------------------------------
function xml_gen(p_limit number) return varchar2;
procedure set_input(p_clob clob);
function next return integer;
function nextall return xpp_array_tab;
procedure run_next;
procedure run_nextall;
procedure run_cnt(p_case number, p_job_cnt number, p_dur_seconds number);
procedure run_job(p_case number, p_job_cnt number, p_dur_seconds number);
procedure run_var(p_case number, p_job_var number, p_dur_seconds number);
end xpp_test;
/
create or replace package body k.xpp_test as
procedure java_setInput(p_clob clob) as
language java name 'XmlPullParserJava.setInput(java.sql.Clob)';
function java_next(p_name out varchar2, p_namespc out varchar2, p_attr_cnt out number, p_text out varchar2, p_elapsed out number)
return pls_integer as
language java name 'XmlPullParserJava.next(java.lang.String[], java.lang.String[], int[], java.lang.String[], long[]) return int';
procedure java_nextall(p_array out xpp_array_tab, p_elapsed out number) as
language java name 'XmlPullParserJava.nextAll(oracle.sql.ARRAY[], long[])';
---------------------------------------------------------------------------
function xml_gen(p_limit number) return varchar2 as
l_level_1 varchar2(32767) := '';
l_level_2 varchar2(32767) := '';
l_level_3 varchar2(32767) := '';
l_xml varchar2(32767);
begin
for i in 1..p_limit loop
l_level_1 := l_level_1||'<TAG_1_'||i||'>text_1_'||i||'</TAG_1_'||i||'>';
end loop;
for i in 1..p_limit loop
l_level_2 := l_level_2||'<TAG_2_'||i||'>'||l_level_1||'</TAG_2_'||i||'>';
end loop;
for i in 1..p_limit loop
l_level_3 := l_level_3||'<TAG_3_'||i||'>'||l_level_2||'</TAG_3_'||i||'>';
end loop;
l_xml := q'[<?xml version="1.0" encoding="UTF-8"?>]'||'<root>'||l_level_3||'</root>';
return l_xml;
end xml_gen;
----------------------------------------------------------------------------
-- simulate XML processing
procedure cpu_burning as
l_cnt number := 10000;
l_x number := 0;
begin
for i in 1..l_cnt loop
l_x := i;
end loop;
end cpu_burning;
----------------------------------------------------------------------------
procedure set_input(p_clob clob) as
begin
java_setInput(p_clob);
end set_input;
----------------------------------------------------------------------------
function next return integer as
begin
return java_next(v_xpp_rec.name, v_xpp_rec.namespc, v_xpp_rec.attr_cnt, v_xpp_rec.text, v_xpp_rec.elapsed);
end next;
---------------------------------------------------------------------------
function nextall return xpp_array_tab as
l_xpp_array_tab xpp_array_tab := new xpp_array_tab();
begin
java_nextall(l_xpp_array_tab, v_xpp_rec.elapsed);
return l_xpp_array_tab;
end nextall;
---------------------------------------------------------------------------
procedure run_next as
l_evt_type pls_integer;
l_name varchar2(32767);
l_text varchar2(32767);
begin
set_input(v_xml_doc);
l_evt_type := next;
loop
case l_evt_type
when 0 then l_name := v_xpp_rec.name;
when 1 then l_name := v_xpp_rec.name;
when 2 then l_name := v_xpp_rec.name;
when 3 then l_name := v_xpp_rec.name;
when 4 then l_text := v_xpp_rec.text;
else null;
end case;
l_evt_type := next;
cpu_burning; -- generate high 'row cache objects'
v_java_call_cnt := v_java_call_cnt + 1;
v_java_call_nano := v_java_call_nano + v_xpp_rec.elapsed;
exit when l_evt_type = 1; -- XPP END_DOCUMENT
end loop;
end run_next;
---------------------------------------------------------------------------
procedure run_nextall as
l_xpp_array_tab xpp_array_tab;
l_name varchar2(32767);
l_text varchar2(32767);
begin
set_input(v_xml_doc);
l_xpp_array_tab := nextall;
v_java_call_cnt := v_java_call_cnt + 1;
v_java_call_nano := v_java_call_nano + v_xpp_rec.elapsed;
for i in 1..l_xpp_array_tab.count loop
case l_xpp_array_tab(i).evt_type
when 0 then l_name := l_xpp_array_tab(i).name;
when 1 then l_name := l_xpp_array_tab(i).name;
when 2 then l_name := l_xpp_array_tab(i).name;
when 3 then l_name := l_xpp_array_tab(i).name;
when 4 then l_text := l_xpp_array_tab(i).text;
else null;
end case;
cpu_burning;
end loop;
end run_nextall;
---------------------------------------------------------------------------
procedure run_cnt(p_case number, p_job_cnt number, p_dur_seconds number)
as
l_cnt number := 0;
l_start_time number := dbms_utility.get_time;
begin
loop
case p_case
when 1 then run_next;
when 2 then run_nextall;
else null;
end case;
l_cnt := l_cnt + 1;
exit when (dbms_utility.get_time - l_start_time) > (p_dur_seconds * 100);
end loop;
insert into test_stats values(systimestamp, p_case, p_job_cnt, p_dur_seconds, l_cnt, v_java_call_cnt, v_java_call_nano);
commit;
end run_cnt;
----------------------------------------------------------------------------
procedure run_job (p_case number, p_job_cnt number, p_dur_seconds number)
as
l_job_id pls_integer;
l_stmt varchar2(1000);
begin
insert into rc_latch_stats
select systimestamp, 'start', p_case, p_job_cnt, v.*
from v$latch v
where name = 'row cache objects';
commit;
for i in 1.. p_job_cnt loop
l_stmt := 'begin xpp_test.run_cnt(' || p_case ||', '
|| p_job_cnt ||', '
|| p_dur_seconds ||
'); end;';
dbms_output.put_line(l_stmt);
dbms_job.submit(l_job_id, l_stmt);
end loop;
commit;
dbms_lock.sleep(p_dur_seconds);
insert into rc_latch_stats
select systimestamp, 'end', p_case, p_job_cnt, v.*
from v$latch v
where name = 'row cache objects';
commit;
dbms_lock.sleep(5);
end run_job;
----------------------------------------------------------------------------
procedure run_var(p_case number, p_job_var number, p_dur_seconds number) as
begin
for job_cnt in 1..p_job_var loop
run_job(p_case, job_cnt, p_dur_seconds);
end loop;
end run_var;
---------------------------------------------------------------------------
begin
v_xml_doc := xml_gen(6); -- XML Doc with length=6681, Tag + Text = 734
end xpp_test;
/