`
fushengxu
  • 浏览: 16657 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

SparkSql 字节码生成技术

阅读更多
    以具体的SQL语句 select a+b fromtable 为例进行说明,下面是它的解析过程:
    1.调用虚函数Add.eval(),需确认Add两边数据类型
    2.调用虚函数a.eval(),需要确认a的数据类型
    3.确认a的数据类型是int,装箱
    4.调用虚函数b.eval(),需确认b的数据类型
    5.确认b的数据类型是int,装箱
    6.调用int类型的add
    7.返回装箱后的计算结果

    从上面的步骤可以看出,一条SQL语句的解析需要进行多次虚函数的调用。我们知道,虚函数的调用会极大的降低效率。那么,虚函数的调用为什么会影响效率呢?
    有人答案是:虚函数调用会进行一次间接寻址过程。事实上这一步间接寻址真的会显著降低运行效率?显然不是。
    流水线的打断才是真正降低效率的原因。
    我们知道,虚函数的调用时是运行时多态,意思就是在编译期你是无法知道虚函数的具体调用。设想一下,如果说不是虚函数,那么在编译时期,其相对地址是确定的,编译器可以直接生成jmp/invoke指令; 如果是虚函数,多出来的一次查找vtable所带来的开销,倒是次要的,关键在于,这个函数地址是动态的,譬如 取到的地址在eax里,则在call eax之后的那些已经被预取进入流水线的所有指令都将失效。流水线越长,一次分支预测失败的代价也就越大,如下所示:

   pf->test
    001E146D mov eax,dword ptr[pf]
    011E1470 mov edx,dword,ptr[eax]
    011E1472 mov esi,esp
    011E1474 mov ecx,dword ptr[pf]
    011E1477 mov eax,dword ptr[edx]
    011E1479 eax <-----------------------分支预测失败
    011E147B cmp esi esp
    011E147D @ILT+355(__RTC_CheckEsp)(11E1168h)

    说到流水线,penalty基本上都是因为气泡(分支指令导致预取失败)。虽然引入流水线极大提高了效率,流水线不是越长越好。
    Scala的运行时反射机制很好机制很好解决了这个问题。未完待续,下回分解。



   
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics