|
cache buffers chains |
kcbgtcr: kslbegin excl |
0 |
1,489 |
1,237 |
|
cache buffers chains |
kcbchg: kslbegin: bufs not pinned |
0 |
618 |
657 |
|
cache buffers chains |
kcbget: pin buffer |
0 |
137 |
54 |
|
cache buffers chains |
kcbchg: kslbegin: call CR func |
0 |
73 |
409 |
|
cache buffers chains |
kcbrls: kslbegin |
0 |
65 |
119 |
|
……………… |
……………… |
“我们的测试语句,就用刚才查到的 ROWID, select * from a2 where rowid=’ AAADZuAAMAAABEEAAA’”,福尔摩斯继续自言自语道,“我们要将它先执行个三、四次,确保它是逻辑读、软软解析。我可不想 Dtrace跟踪出的结果有一大堆硬解析的东西。” 华生在一边说:“是啊,记得跟踪过一次硬解析,好像十分的复杂,比软软解析复杂十倍都不止。” 说话间,福尔摩斯已经将测试语句 select * from a2 where rowid=’ AAADZuAAMAAABEEAAA’在测试会话执行了 5、 6遍。 “可以开始跟踪了。”华生说。 福尔摩斯点点了头,执行了他们常用的 Dtrace脚本,脚本非常简单,也就下面几行: #!/usr/s bin/dtrace -s -n dtrace:::BEGIN { i=1; } pid$1:::entry { printf("i=%d PID::entry:==%s:%s:%s:%s %x %x %x %x %x %x",i, probeprov, probemod, probefunc, probename,arg0,arg1,arg2,arg3,arg4,arg5); i=i+1; }
| 这么简单的函数,相信应该是用C语言的内嵌汇编写的。现在,进程正停在sskgslcas的入口处,福尔摩斯看了一下寄存器的值: > $r %rax = 0x0000000000000000 %r8 = 0x0000000000000000 %rbx = 0x0000000000000000 %r9 = 0x00000003927628d8 %rcx = 0x0000000000000000 %r10 = 0x00000003911a7e88 %rdx = 0x0000000000000001 %r11 = 0xfffffd7ffcd01f00 %rsi = 0x0000000000000000 %r12 = 0x00000003911f52e8 %rdi = 0x00000003911f4318 %r13 = 0x0000000392762790 %r14 = 0xfffffd7ffc924720 %r15 = 0x0000000000000001 这要要说明一下的是,从左边rdi寄存器开始,rsi、rdx等,依次是调用函数的第一个、第二个、第三个等等参数。 Sskgslcas中第一条指令: sskgslcas: movq %rsi,%rax 将函数的第二个参数传给rax寄存器,从上面展示的结果,第二个参数,也就是rsi的值为0。 Sskgslcas下一条指令: sskgslcas+3: lock cmpxchgq %rdx,(%rdi) 它在sskgslcas函数入口处向后3字节, “这说明第一条指令‘movq %rsi,%rax’占了三个字节。”福尔摩斯向华生解释道。 Lock是锁总线的,cmpxchgq是测试并交换,test&swap,将两个操作封装在一条指令中,由CPU保证这两个操作的原子性。在多芯、多核的系统中,加Lock是必须的。 福尔摩斯又向华生解释:“cmpxchgq会首先用(%rdi)处的内存值和rdx寄存品的值相比较,比较结果将会影响标志寄存器。如果比较结果不相等,会将rdx的值传入内存(%rdi)处。如果比较结果相等,则不再将rdx的值传入内存(%rdi)处” 华生一脸的疑惑,显然还没看懂,福尔摩斯问道:“你不是有二级C语言的基础吗,哪你应该能看懂下面这段C C语言伪码。” 说着,福尔摩斯写下这段伪码: If ( (rdi) != rdx ) { (rdi) = rdx ; } “嗯,”,看了一几行代码,华生有点懂了。“因为我们已经用oradebug poke,将Latch地址处的内存值设置为1。所以这里Cmpxchgq测试结果不成功,等于Latch没有加上。” “是的。”,福尔摩斯说道,“汇编和C语言不同,汇编要直接操作硬件,现代CPU架构中,任何比较语句,都会引起标志寄存器的改变。所以,无论条件语句中的(rdi) = rdx ;语句是否被执行,(rdi) != rdx这个比较语句,都会改变一些标志寄存器的值。” “因此,”,福尔摩斯顿了一顿,继续说道,“下一条语句就是从标志寄存器中取结果了” 下两条语句是: sskgslcas+8: sete %al sskgslcas+0xb: movzbq %al,%rax 华生赶忙Google了一下,sete,地ZF标志寄存器的值传送到al寄存器。这次福尔摩斯没有做过多解释,直接写了行C伪码: Al = ( (rdi) != rdx ) 华生一看就明白了,“sete %al,相当于将(rdi) != rdx比较的结果,送入al寄存器。” “差不多吧,”,福尔摩斯笑笑答道。 “此处,(rdi)和rdx相等,条件不成立,送进al的值,就是0了。”华生道。 “是的。”福尔摩斯回答说,“而下面一条指令,movzbq,就简单了,将8位的al寄存器值,扩展到64的rax中,然后,就是ret了,按照汇编的惯例,返回值一定要在rax寄存器中,整个来看,这段代码就如同下面这段C语言代码。” 福尔摩斯写下了下面这段代码: Int sskgslcas(rdi,rsi,rdx,rcx) { If ( al = (rdi) != rdx ) { (rdi) = rdx ; } Return al; } 这就是CBC Latch函数和Mutex的伪码了。 华生看了一会儿,在心中默默的想了一遍,就明白了,“sskgslcas的结果在rax寄存器,如果Latch申请成功,rax为1,如果申请不成功,rax为0,是这样的吧。”华生问道。 “是这样的。”福尔摩斯答道,“让我们单步执行,验证一下。” 说着,他在mdb中使用::step,让进程一直执行到ret处: > ::step mdb: target stopped at: sskgslcas+0xf: ret 查一下此进寄存器的值: > $r %rax = 0x0000000000000000 %r8 = 0x0000000000000000 %rbx = 0x0000000000000000 %r9 = 0x00000003927628d8 %rcx = 0x0000000000000000 %r10 = 0x00000003911a7e88 %rdx = 0x0000000000000001 %r11 = 0xfffffd7ffcd01f00 %rsi = 0x0000000000000000 %r12 = 0x00000003911f52e8 %rdi = 0x00000003911f4318 %r13 = 0x0000000392762790 %r14 = 0xfffffd7ffc924720 %r15 = 0x0000000000000001 Rax果然为0。申请Latch没有成功。 看到单步执行结果和他们分析的一样,福尔摩斯和华生相视一笑。 “接下来要做什么?”华生问道。 福尔摩斯笑着骂道,“动动脑子想想啊,sskgslcas函数已经分析完了,接下来做啥。” “从sskgslcas调用处,继续分析kcbgtcr。”华生肯定的回答。 “你开窃了,华生。”福尔摩斯开了句玩笑,手中没停,拿过刚才所汇编kcbgtcr的结果,从刚才的位置继续向下看: kcbgtcr+0x2788: call +0x6894f08 <sskgslcas> 根据ROWID逻辑读时的第一次CBC Latch kcbgtcr+0x278d: testl %eax,%eax kcbgtcr+0x278f: jne +0x48 <kcbgtcr+0x27d7> kcbgtcr+0x2791: movq $0x0,0x450(%r13) kcbgtcr+0x279c: testl %r15d,%r15d kcbgtcr+0x279f: movl $0x0,%eax kcbgtcr+0x27a4: movl $0x40,%ecx kcbgtcr+0x27a9: movl %eax,%esi kcbgtcr+0x27ab: cmovl.e %ecx,%esi kcbgtcr+0x27ae: orl $0x109,%esi kcbgtcr+0x27b4: movl 0x4(%r14),%eax kcbgtcr+0x27b8: movl %eax,%ecx kcbgtcr+0x27ba: movq 0xa718147 (%rip),%r8 kcbgtcr+0x27c1: movl (%r8),%r8d kcbgtcr+0x27c4: movq -0x698(%rbp),%rdi kcbgtcr+0x27cb: movl $0x1,%edx kcbgtcr+0x27d0: call -0x1202260 <kslgess> kcbgtcr+0x27d5: jmp +0x53 <kcbgtcr+0x2828> kcbgtcr+0x27d7: movq 0xaf571ca(%rip),%r8 d7f1bf0->r8 这次华生已经不再畏惧,主动说到,“调用sskgslcas返回,下一条语句是testl %eax,%eax,看来这是在比较Latch的申请是否成功了。” “是的”,福尔摩斯说到,“jne是不相等或非零跳转,这两行语句,相当于。”说着,他又写下了如下的伪码: kcbgtcr+0x278d: testl %eax,%eax kcbgtcr+0x278f: jne +0x48 <kcbgtcr+0x27d7> 相当于: if ( eax != 0 ) { goto <kcbgtcr+0x27d7>; } “Eax不等于零就跳转,”华生惊叫道,“这是判断Latch是否申请成功的,如果Latch申请成功就跳到kcbgtcr+0x27d7处。” 福尔摩斯冲着华生眨了眨眼,道:“瞧,我们离目标越来越近了,好像没也没什么难的,不是吗!”。 “是啊,”华生接着说:“被跳过去的部分,就是当Latch没有申请成功的话,Oracle会执行的代码。” 福尔摩斯道:“是的,我肯定案犯也来过这里,我们要仔细调查这段代码。” 这段代码是: kcbgtcr+0x278f: jne +0x48 <kcbgtcr+0x27d7> kcbgtcr+0x2791: movq $0x0,0x450(%r13) kcbgtcr+0x279c: testl %r15d,%r15d kcbgtcr+0x279f: movl $0x0,%eax kcbgtcr+0x27a4: movl $0x40,%ecx kcbgtcr+0x27a9: movl %eax,%esi kcbgtcr+0x27ab: cmovl.e %ecx,%esi kcbgtcr+0x27ae: orl $0x109,%esi kcbgtcr+0x27b4: movl 0x4(%r14),%eax kcbgtcr+0x27b8: movl %eax,%ecx kcbgtcr+0x27ba: movq 0xa718147 (%rip),%r8 kcbgtcr+0x27c1: movl (%r8),%r8d kcbgtcr+0x27c4: movq -0x698(%rbp),%rdi kcbgtcr+0x27cb: movl $0x1,%edx kcbgtcr+0x27d0: call -0x1202260 <kslgess> kcbgtcr+0x27d5: jmp +0x53 <kcbgtcr+0x2828> kcbgtcr+0x27d7: movq 0xaf571ca(%rip),%r8 d7f1bf0->r8 “看,这段代码中调用了一个函数,kslgess。”华生叫到。 “是的,它一定和Latch Miss有关,单步执行到它哪里。”福尔摩斯说道。 接着,他用::step,一路执行下去,直到在调用kslgess处停下: > ::step mdb: target stopped at: kcbgtcr+0x27d0: call -0x1202260 <kslgess> 用$r显示kslgess的参数: > ::step mdb: target stopped at: kcbgtcr+0x27d0: call -0x1202260 <kslgess> > $r %rax = 0x0000000003001104 %r8 = 0x000000000000067e %rbx = 0x0000000000000000 %r9 = 0x00000003927628d8 %rcx = 0x0000000003001104 %r10 = 0x00000003911a7e88 %rdx = 0x0000000000000001 %r11 = 0xfffffd7ffcd01f00 %rsi = 0x0000000000000109 %r12 = 0x00000003911f52e8 %rdi = 0x00000003911f4318 %r13 = 0x0000000392762790 %r14 = 0xfffffd7ffc924720 %r15 = 0x0000000000000001 “看到r8没”,福尔摩斯说,“67e,这个值有问题,我看,它就是Latch Miss。” 未等福尔摩斯吩咐,华生已经将验正语句准备好: set linesize 1000 col KSLLWNAM for a30 col KSLLWLBL for a20 col KSLLASNAM for a40 select a.addr,b.addr,a.KSLLWNAM, a.KSLLWLBL,b.KSLLASNAM from x$ksllw a,x$kslwsc b where a.indx=b.indx and a.indx=to_number('&aa','xxxxxxxx'); 执行结果是: Enter value for aa: 67e old 1: select a.addr,b.addr,a.KSLLWNAM,a.KSLLWLBL,b.KSLLASNAM from x$ksllw a,x$kslwsc b where a.indx=b.indx and a.indx=to_number('&aa','xxxxxxxx') new 1: select a.addr,b.addr,a.KSLLWNAM,a.KSLLWLBL,b.KSLLASNAM from x$ksllw a,x$kslwsc b where a.indx=b.indx and a.indx=to_number('67e','xxxxxxxx') ADDR ADDR KSLLWNAM KSLLWLBL KSLLASNAM ---------------- ---------------- ------------------------------ -------------------- ---------------------------------------- 000000000CFC1F08 00000003926F9AA0 kcbgtcr: fast path (cr pin) cache buffers chains “Oh yeah!”,华生叫道:“67e是kcbgtcr: fast path (cr pin)的代码。” 福尔摩斯道:“别哪么快下结论,验证一下。” 华生马上写了一下PL/SQL程序: declare v_id1 number; begin for i in 1..10000000 loop select id1 into v_id1 from a2 where rowid='AAADZuAAMAAABEEAAA'; end loop; end; / 在两个会话中执行,两个进程疯狂读同一块,一定会有大量CBC Latch竞争,查询V$Latch_misses视图,果然发现kcbgtcr: fast path (cr pin)的SLEEP_COUNT大量增加。 看来,调用kslgess时,r8寄存器的值果然就是latch miss的Location编号。 其他的Latch函数,如kslgetl,它的形式如下: Kslgetl(Latch地址,未知,未知,Where,……) 第四个参数Where,就是Latch Miss。 Sskgslcas不一样,这个函数看来是只用于非常繁忙的CBC Latch和Mutex。它在被调用时没有Latch Miss,如果申请Latch、Mutex失败,再通过kslgess函数登记Latch Miss信息。 忙了半天,终于小有进展。 福尔摩斯说道:“下面分析一下r8寄存器的值从哪里来的。” 关于r8,有下面两行代码: kcbgtcr+0x27ba: movq 0xa718147 (%rip),%r8 kcbgtcr+0x27c1: movl (%r8),%r8d 0xaf5d827(%rip),这也能算是一个“PC相关地址”,rip是PC指令寄存器,记录下一条要执行的指令代码的内存地址。0xa718147 (%rip)的值如何求呢? 福尔摩斯没等华生问,就写出了如下的方法 kcbgtcr+0x27ba+0xa718147 华生在mdb中使用dump命令,显示了一下: > kcbgtcr+0x27ba+0xa718147,8::dump -e ceaf9a1: 038001aa b0000000 038001aa b8000000 得到一个内存地址:038001aab0。 下一步“movl (%r8),%r8d”,就是将此内存地址处的值,传给r8。显示一下此内存地址的值: > 038001aab0,8::dump -e 38001aab0: 0000067e 00000000 0000067f 00000000 正好是67e。也就是kcbgtcr: fast path (cr pin)。 福尔摩斯说:“看华生,有了些进展。我们并不需要反汇编所有代码,只需要找到我们感兴趣的部分就行。” 华生说:“是的,但是这个kcbgtcr: fast path (cr pin),并不是罪案现场的kcbgtcr: kslbegin excl啊。” 福尔摩斯说:“嗯,是的。我们有了进展,但还没有最终找到结果。” 华生说:“不过,也算是有成果了,最普通的逻辑读,或者说一致读,Latch Miss是kcbgtcr: fast path (cr pin)。原凶并不是普通的逻辑读。” 福尔摩斯问道:“想一想,华生,接下来要怎么做!” 华生说:“可以将kcbgtcr所有kslgess找到,查看kcbgtcr: kslbegin excl会在哪儿。” 福尔摩斯说:“对,立即行动。” 华生答:“Yes,Sr。” 华生将kcbgtcr的反汇编代码放入一个文本文件,统计了一下: bash-3.2# cat kcbgtcr.asm|grep kslgess kcbgtcr+0x537: call -0x11fffc7 <kslgess> kcbgtcr+0x27d0: call -0x1202260 <kslgess> kcbgtcr+0x5bb3: call -0x1205643 <kslgess> kcbgtcr+0x61f5: call -0x1205c85 <kslgess> kcbgtcr+0x644e: call -0x1205ede <kslgess> kcbgtcr+0x9777: call -0x1209207 <kslgess> 不多,只有6处。Kcbgtcr函数只在6个地方用sskgslcas申请CBC Latch。它们分别对应的Latch Miss是: 1、kcbgtcr+0x521: movq 0xaf5f9e0(%rip),%r8 ---662 kcbgtcr: fast path 2、kcbgtcr+0x27ba: movq 0xa718147 (%rip),%r8 ---- kcbgtcr: fast path (cr pin) 3、kcbgtcr+0x5ba9: movq 0xaf5a360(%rip),%r8 ---- 0x663 kcbgtcr: kslbegin excl 4、kcbgtcr+0x61eb: movq 0xaf59eae(%rip),%r8 --- 695 kcbgtcr_2 5、kcbgtcr+0x6444: movq 0xaf599bd(%rip),%r8 --- 642 kcbgtcr: kslbegin shared 6、kcbgtcr+0x976d: movq 0xaf56a0c(%rip),%r8 ---6b1 kcbgtcr: L2 其中,kcbgtcr+0x27ba处的,是刚刚发现的、普通逻辑读处的Latch Miss。案犯现场的目标:kcbgtcr: kslbegin excl,在偏移量kcbgtcr+0x5ba9处。 看到这个结果,福尔摩斯和华生都长出了一口气,kcbgtcr: kslbegin excl终于现形了。但新的问题又来了,kcbgtcr+0x5ba9,Oracle在什么情况下才会执行到这里呢?可以肯定的时,这不是最普通的物理读,因为最普通的物理读,Latch Miss是kcbgtcr+0x27ba处的kcbgtcr: fast path (cr pin)。 福尔摩斯和华生想了很多情况,但都不能找到什么情况下Oracle才会走到kcbgtcr: kslbegin excl这里。最后,福尔摩斯狠下心来,从kcbgtcr的头开始,单步执行,一步步跟踪。 “先把kcbgtcr函数的原理搞清楚”,福尔摩斯说,“不然,我们发现不了Oracle什么时候会执行kcbgtcr: kslbegin excl这里。” “也只好如此了,”华生举目沮丧的说到。 他们开始从kcbgtcr的第一个字节处分析反汇编代码,过程有点无聊,长话短说吧,从kcbgtcr+0x2c0处到kcbgtcr+0x385处,是Buffer Cache中的HASH算法: kcbgtcr+0x2c0: movq 0xa723e59(%rip),%r8 kcbgtcr+0x2c7: movl 0x80(%r8),%eax kcbgtcr+0x2ce: incl %eax kcbgtcr+0x2d0: andl $0xf,%eax kcbgtcr+0x2d3: movq 0xa723e46(%rip),%r8 kcbgtcr+0x2da: movl %eax,0x80(%r8) kcbgtcr+0x2e1: movl (%r14),%eax kcbgtcr+0x2e4: movq 0xa723e35(%rip),%r8 kcbgtcr+0x2eb: movq 0xa723e2e(%rip),%r9 kcbgtcr+0x2f2: movl 0x80(%r9),%ecx kcbgtcr+0x2f9: movl %ecx,%r9d kcbgtcr+0x2fc: movl %eax,(%r8,%r9,8) kcbgtcr+0x300: movl 0x4(%r14),%eax kcbgtcr+0x304: movq 0xa723e15(%rip),%r8 kcbgtcr+0x30b: movq 0xa723e0e(%rip),%r9 kcbgtcr+0x312: movl 0x80(%r9),%ecx kcbgtcr+0x319: movl %ecx,%r9d kcbgtcr+0x31c: movl %eax,0x4(%r8,%r9,8) kcbgtcr+0x321: movq 0xa714018(%rip),%r8 kcbgtcr+0x328: movl (%r8),%eax kcbgtcr+0x32b: movl %eax,-0x448(%rbp) kcbgtcr+0x331: movl (%r14),%eax kcbgtcr+0x334: shll $0x11,%eax kcbgtcr+0x337: addl 0x4(%r14),%eax kcbgtcr+0x33b: imull $0x9e370001,%eax,%eax kcbgtcr+0x341: movq 0xa72ed30(%rip),%r8 kcbgtcr+0x348: movl (%r8),%ecx kcbgtcr+0x34b: movl %eax,%edx kcbgtcr+0x34d: shrl %cl,%edx kcbgtcr+0x34f: movq 0xa72ed2a(%rip),%r8 kcbgtcr+0x356: movl (%r8),%eax kcbgtcr+0x359: andl %edx,%eax kcbgtcr+0x35b: movl %eax,%r8d kcbgtcr+0x35e: shlq $0x4,%r8 kcbgtcr+0x362: movq 0xa72ed1f(%rip),%r9 kcbgtcr+0x369: movl (%r9),%ecx kcbgtcr+0x36c: movl %edx,%eax kcbgtcr+0x36e: shrl %cl,%eax kcbgtcr+0x370: movl %eax,%r9d kcbgtcr+0x373: shlq $0x4,%r9 kcbgtcr+0x377: movq 0xa72ed12(%rip),%r10 kcbgtcr+0x37e: movq (%r10),%r10 kcbgtcr+0x381: movq (%r10,%r9),%r12 kcbgtcr+0x385: addq %r8,%r12 这段代码对应的C语言伪码是: int sp1=0x11; int sp2=0x7f; int sp3=0x7; int hash_header=0x394953140; hash(int p1,int p2) { int uk=p1; int rdba=p2; int v1,v2; int target_addr; uk=uk<<0x11+rdba; uk=(0x9e370001*uk)&0x00000000FFFFFFFF; uk=uk>>sp1; v1=uk&sp2; v1=v1<<0x4; v2=uk>>0xsp3; v2=v2<<0x4; target_addr=hash_header+v2+v1; } 通过解析反汇编代码,对于HASH运算消耗的CPU,更加清楚了。 在算法出HASH值后,执行流程会跳到kcbgtcr+0x25b1处,从这里开始,是申请CBC Latch的准备工作。然后在kcbgtcr+0x2788处,就是申请CBC Latch了,在它后面,就是开始搜索HASH链了,在这之后,有如下的代码: kcbgtcr+0x281d: movl 0x4(%r14),%eax kcbgtcr+0x2821: movl %eax,%r9d kcbgtcr+0x2824: movq %r9,0x18(%r8) kcbgtcr+0x2828: cmpq (%r12),%r12 kcbgtcr+0x282c: movq $0x0,%r8 kcbgtcr+0x2833: movq %r8,-0x5f0(%rbp) kcbgtcr+0x283a: movl $0x0,-0x5c8(%rbp) kcbgtcr+0x2844: movl $0x0,-0x5d0(%rbp) kcbgtcr+0x284e: movl $0x0,-0x664(%rbp) kcbgtcr+0x2858: je +0x2fe8 <kcbgtcr+0x5840> 在kcbgtcr+0x281d处,从r14寄存器向下偏移4字节传入eax的值,是被读块的dba。R12寄存器的值,是HASH Bucket中CBC链的链表头。“cmpq (%r12),%r12”是判断CBC链是否为空。还记得前面所画的CBC链图吗,如果链表是空的,Bucket中记录Bucket本身的地址。也就是Bucket自已指向自己。cmpq (%r12),%r12正是比较r12指向的内容和r12是否相等。如果相等,Bucket后就没有链表。 如果链表为空,证明块一定不在Buffer Cache,kcbgtcr+0x2858处的“je +0x2fe8 <kcbgtcr+0x5840>”,会让程序执行流程跳到kcbgtcr+0x5840处。 这充分说明kcbgtcr+0x5840后的代码,是处理物理读的。 如果CBC链不为空,下面的代码就是遍历CBC链,这行代码: kcbgtcr+0x289c: movq (%r8),%r8 这句的意义是将指针指向的值赋给指针,类似于这样的代码:prt_next=*ptr_next 。这句正是用来遍历CBC链表的。 紧接着这三行,将注释直接写在代码后: kcbgtcr+0x2918: movl 0x4(%r14),%eax // 将dba传给eax寄存器,作为目标dba kcbgtcr+0x291c: cmpl %eax,0xc4(%r13) // 寄存器r13记录BH地址,向下偏移0xc4字节, 就是BH中的dba,用eax中的目标dba和此dba比较。 kcbgtcr+0x2923: jne +0x1857 <kcbgtcr+0x417a> // 如果不匹配,跳转。 跳转过去之后,有如下的代码: kcbgtcr+0x4195: movq %r8,-0x5a0(%rbp) kcbgtcr+0x419c: movq -0x5a0(%rbp),%r8 kcbgtcr+0x41a3: testq %r8,%r8 kcbgtcr+0x41a6: jne -0x18a6 <kcbgtcr+0x2900> //当CBC链没到头时,回以刚才的地方, 继续查找。 kcbgtcr+0x41ac: jmp +0x9 <kcbgtcr+0x41b5> kcbgtcr+0x41ae: movq %r13,-0x608(%rbp) kcbgtcr+0x41b5: cmpq $0x0,-0x608(%rbp) kcbgtcr+0x41bd: je +0x1683 <kcbgtcr+0x5840> //如果CBC链搜索完毕没找到目标dba, 跳转到kcbgtcr+0x5840处。 kcbgtcr+0x41c3: movzwl 0xbc(%r14),%eax 也就是说,CBC链中没找到目标时(也就是物理读时),将跳到kcbgtcr+0x5840处。 看看kcbgtcr+0x5840代码吧: kcbgtcr+0x583d: popq %rbx kcbgtcr+0x583e: leave kcbgtcr+0x583f: ret kcbgtcr+0x5840: movl -0x5b8(%rbp),%eax kcbgtcr+0x5846: testl %eax,%eax 在kcbgtcr+0x583f处,有指令ret,kcbgtcr到这里有可能结束,返回调用者。程序什么时候会跳到kcbgtcr+0x5840处呢,物理读。 纯逻辑读,kcbgtcr函数的执行,会在kcbgtcr+0x583f处终止。物理读则会跳至kcbgtcr+0x5840后开始执行。 经过艰难的调查取证,福尔摩斯和华生终于大概搞清楚了kcbgtcr的执行流程。 华生看了一眼作案现场留下的线索:kcbgtcr: kslbegin excl,轻轻的喃喃自语:“终于抓到你了。” 有没有忘掉kcbgtcr: kslbegin excl在代码的哪里: kcbgtcr+0x5ba9: movq 0xaf5a360(%rip),%r8 ---- 0x663 kcbgtcr: kslbegin excl kcbgtcr+0x5ba9,在kcbgtcr+0x5840之后不远的位置,这块代码,只有物理读才有可能走到这里。 所以,原凶就是:“物理读”。 这真是一个奇怪的结果,逻辑读函数中的Latch竞争,原凶竟然是物理读。 调优的方向,应该是针对物理读最多的一些SQL,这样才有助于减少kcbgtcr: kslbegin excl处的Latch争用。 而这调优逻辑读高的SQL,对于减少kcbgtcr: kslbegin excl处的Latch争用,是没有帮助的。 进一步的,可以将kcbgtcr中的Latch Miss分个类: 一、纯逻辑读相关的 1、kcbgtcr+0x521: movq 0xaf5f9e0(%rip),%r8 ---662 kcbgtcr: fast path 2、kcbgtcr+0x27ba: movq 0xa718147 (%rip),%r8 ---- kcbgtcr: fast path (cr pin) 二、物理读相关的: 3、kcbgtcr+0x5ba9: movq 0xaf5a360(%rip),%r8 ---- 0x663 kcbgtcr: kslbegin excl 4、kcbgtcr+0x61eb: movq 0xaf59eae(%rip),%r8 --- 695 kcbgtcr_2 5、kcbgtcr+0x6444: movq 0xaf599bd(%rip),%r8 --- 642 kcbgtcr: kslbegin shared 6、kcbgtcr+0x976d: movq 0xaf56a0c(%rip),%r8 ---6b1 kcbgtcr: L2 |

更多内容请关注微信公众号:数据与人
编辑推荐:
相关推荐
-
雷神推出 MIX PRO II 迷你主机:基于 Ultra 200H,玻璃上盖 + ARGB 灯效
2 月 9 日消息,雷神 (THUNDEROBOT) 现已宣布推出基于英
-
制造商 Musnap 推出彩色墨水屏电纸书 Ocean C:支持手写笔、第三方安卓应用
2 月 10 日消息,制造商 Musnap 现已在海外推出一款 Oce
热文推荐
- 【转】CBC Latch的kcbgtcr: kslbegin excl 揭密
- Oracle 19C OGG基础运维-01环境准备
Oracle 19C OGG基础运维-01环境准备
26-03-03 - 从零到一 | 如何搭建数据库自动化运维体系
从零到一 | 如何搭建数据库自动化运维体系
26-03-03 - Oracle 19C OGG基础运维-02数据初始化
Oracle 19C OGG基础运维-02数据初始化
26-03-03 - 力软(learun)框架:十年磨一剑,一朝试锋芒
力软(learun)框架:十年磨一剑,一朝试锋芒
26-03-03 - Oracle数据库性能优化的艺术 (文平) 高清PDF扫描版[41M]下载
- Oracle 19C OGG基础运维-03DML操作同步
Oracle 19C OGG基础运维-03DML操作同步
26-03-03 - RAC中GPNP 文件相关及修改
RAC中GPNP 文件相关及修改
26-03-03 - Oracle 19C OGG基础运维-04DML同步常见问题
Oracle 19C OGG基础运维-04DML同步常见问题
26-03-03 - Oracle RAC 11g实战指南(刘宪军) PDF扫描版[20MB]高清下载
