精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

編譯優(yōu)化 | LLVM代碼生成技術(shù)詳解及在數(shù)據(jù)庫中的應(yīng)用

運維 數(shù)據(jù)庫運維
隨著IT基礎(chǔ)設(shè)施的發(fā)展,現(xiàn)代的數(shù)據(jù)處理系統(tǒng)需要處理更多的數(shù)據(jù)、支持更為復雜的算法。數(shù)據(jù)量的增長和算法的復雜化,為數(shù)據(jù)分析系統(tǒng)帶來了嚴峻的性能挑戰(zhàn)。

 [[407375]]

1. 前言

隨著IT基礎(chǔ)設(shè)施的發(fā)展,現(xiàn)代的數(shù)據(jù)處理系統(tǒng)需要處理更多的數(shù)據(jù)、支持更為復雜的算法。數(shù)據(jù)量的增長和算法的復雜化,為數(shù)據(jù)分析系統(tǒng)帶來了嚴峻的性能挑戰(zhàn)。近年來,我們可以在數(shù)據(jù)庫、大數(shù)據(jù)系統(tǒng)和AI平臺等領(lǐng)域看到很多性能優(yōu)化的技術(shù),技術(shù)涵蓋體系結(jié)構(gòu)、編譯技術(shù)和高性能計算等領(lǐng)域。作為編譯優(yōu)化技術(shù)的代表,本文主要介紹基于LLVM的代碼生成技術(shù)(簡稱Codeden)。

LLVM是一款非常流行的開源編譯器框架,支持多種語言和底層硬件。開發(fā)者可以基于LLVM搭建自己的編譯框架并進行二次開發(fā),將不同的語言或者邏輯編譯成運行在多種硬件上的可執(zhí)行文件。對于Codegen技術(shù)來說,我們主要關(guān)注LLVM IR的格式以及生成LLVM IR的API。在本文的如下部分,我們首先對LLVM IR進行介紹,然后介紹Codegen技術(shù)的原理和使用場景,最后我們介紹在阿里云自研的云原生數(shù)據(jù)倉庫產(chǎn)品AnalyticDB PostgreSQL中,Codegen的典型應(yīng)用場景。

2. LLVM IR簡介及上手教程

在編譯器理論與實踐中,IR是非常重要的一環(huán)。IR的全稱叫做Intermediate Representation,翻譯過來叫“中間表示”。 對于一個編譯器來說,從上層抽象的高級語言到底層的匯編語言,要經(jīng)歷很多個環(huán)節(jié)(pass),經(jīng)歷不同的表現(xiàn)形式。而編譯優(yōu)化技術(shù)有很多種,每種技術(shù)作用的編譯環(huán)節(jié)不同。但是IR是一個明顯的分水嶺。IR以上的編譯優(yōu)化,不需要關(guān)心底層硬件的細節(jié),比如硬件的指令集、寄存器文件大小等。IR以下的編譯優(yōu)化,需要和硬件打交道。LLVM最為著名是它的IR的設(shè)計。得益于巧妙地IR設(shè)計,LLVM向上可以支持不同的語言,向下可以支持不同的硬件,而且不同的語言可以復用IR層的優(yōu)化算法。

 

 

 

 

 

 

上圖展示了LLVM的一個框架圖。LLVM把整個編譯過程分為三步:(1)前端,把高級語言轉(zhuǎn)換為IR。(2)中端,在IR層做優(yōu)化。(3) 后端,把IR轉(zhuǎn)化為對應(yīng)的硬件平臺的匯編語言。因此LLVM的擴展性很好。比如你要實現(xiàn)一個名為toyc的語言、希望運行在ARM平臺上,你只需要實現(xiàn)一個toyc->LLVM IR的前端,其他部分調(diào)LLVM的模塊就可以了。或者你要搞一個新的硬件平臺,那么只需要搞定LLVM IR->新硬件這一階段,然后該硬件就可以支持很多種現(xiàn)存的語言。因此,IR是LLVM最有競爭力的地方,同時也是學習使用LLVM Codegen的最核心的地方。

2.1 LLVM IR基本知識

LLVM的IR格式非常像匯編,對于學習過匯編語言的同學來說,學會使用LLVM IR進行編程非常容易。對于沒學過匯編語言的同學,也不用擔心,匯編其實并不難。匯編難的不是學會,而是工程實現(xiàn)。因為匯編語言的開發(fā)難度,會隨著工程復雜度的提升呈指數(shù)級上升。接下來我們需要了解IR中最重要的三部分,指令格式、Basic Block & CFG,還有SSA。完整的LLVM IR信息請參考https:// llvm.org/docs/LangRef.h tml 。

指令格式 。LLVM IR提供了一種類似于匯編語言的三地址碼式的指令格式。下面的代碼片段是一個非常簡單的用LLVM IR實現(xiàn)的函數(shù),該函數(shù)的輸入是5個i32類型(int32)的整數(shù),函數(shù)的功能是計算這5個數(shù)的和并返回。LLVM IR是支持一些基本的數(shù)據(jù)類型的,比如i8、i32、浮點數(shù)等。LLVM IR中得變量的命名是以 "%"開頭,默認%0是函數(shù)的第一個參數(shù)、%1是第二個參數(shù),依次類推。機器生成的變量一般是以數(shù)字進行命名,如果是手寫的話,可以根據(jù)自己的喜好選擇合適的命名方法。LLVM IR的指令格式包括操作符、類型、輸入、返回值。例如 "%6 = add i32 %0, %1"的操作符號是"add"、類型是"i32"、輸入是"%0"和“%1”、返回值是"%6"。總的來說,IR支持一些基本的指令,然后編譯器通過這些基本指令的來完成一些復雜的運算。例如,我們在C中寫一個形如“A * B + C”的表達式在LLVM IR中是通過一條乘法和一條加法指令來完成的,另外可能也包括一些類型轉(zhuǎn)換指令。

  1. define i32 @ir_add(i32, i32, i32, i32, i32){ 
  2.   %6 = add i32 %0, %1 
  3.   %7 = add i32 %6, %2 
  4.   %8 = add i32 %7, %3 
  5.   %9 = add i32 %8, %4 
  6.   ret i32 %9 

Basic Block & CFG 。了解了IR的指令格式以后,接下來我們需要了解兩個概念:Basic Block(基本塊,簡稱BB)和Control Flow Graph(控制流圖,CFG)。下圖(左)展示了一個簡單的C語言函數(shù),下圖(中)是使用clang編譯出來的對應(yīng)的LLVM IR,下圖(右)是使用graphviz畫出來的CFG。結(jié)合這張圖,我們解釋下Basic Block和CFG的概念。

 

 

 

 

 

 

在我們平時接觸到的高級語言中,每種語言都會有很多分支跳轉(zhuǎn)語句,比如C語言中有for, while, if等關(guān)鍵字,這些關(guān)鍵字都代表著分支跳轉(zhuǎn)。開發(fā)者通過分支跳轉(zhuǎn)來實現(xiàn)不同的邏輯運算。匯編語言通常通過有條件跳轉(zhuǎn)和無條件跳轉(zhuǎn)兩種跳轉(zhuǎn)指令來實現(xiàn)邏輯運算,LLVM IR同理。比如在LLVM IR中"br label %7"意味著無論如何都跳轉(zhuǎn)到名為%7的label那里,這是一條無條件跳轉(zhuǎn)指令。"br i1 %10, label %11, label %22"是有條件跳轉(zhuǎn),意味著這如果%10是true則跳轉(zhuǎn)到名為%11的label,否則跳轉(zhuǎn)到名為%22的label。

在了解了跳轉(zhuǎn)指令這個概念后,我們介紹Basic Block的概念。一個Basic Block是指一段串行執(zhí)行的指令流,除了最后一句之外不會有跳轉(zhuǎn)指令,Basic Block入口的第一條指令叫做“Leading instruction”。除了第一個Basic Block之外,每個Basic Block都會有一個名字(label)。第一個Basic Block也可以有,只是有時候沒必要。例如在這段代碼當中一共有5個Basic Block。Basic Block的概念,解決了控制邏輯的問題。通過Basic Block, 我們可以把代碼劃分成不同的代碼塊,在編譯優(yōu)化中,有的優(yōu)化是針對單個Basic Block的,有些是針對多個Basic Block的。

CFG(Control Flow Graph, 控制流圖)其實就是由Basic Block以及Basic Block之間的跳轉(zhuǎn)關(guān)系組成的一個圖。例如上圖所示的代碼,一共有5個Basic Block,箭頭列出了Basic Block之間的跳轉(zhuǎn)關(guān)系,共同組成了一個CFG。如果一個Basic Block只有一個箭頭指向別的Block,那么這個跳轉(zhuǎn)就是無條件跳轉(zhuǎn),否則是有條件跳轉(zhuǎn)。CFG是編譯理論中一個比較簡單而且很基礎(chǔ)的概念,CFG更進一步是DFG(Data Flow Graph,數(shù)據(jù)流圖),很多進階的編譯優(yōu)化算法都是基于DFG的。對于使用LLVM進行Codegen開發(fā)的同學,理解CFG的概念即可。

SSA 。SSA的全稱是Static Single Assignment(靜態(tài)單賦值),這是編譯技術(shù)中非常基礎(chǔ)的一個理念。SSA是學習LLVM IR必須熟悉的概念,同時也是最難理解的一個概念。細心的讀者在觀察上面列出的IR代碼時會發(fā)現(xiàn),每個“變量”只會被賦值一次,這就是SSA的核心思想。因為從編譯器的角度來看,編譯器不關(guān)心“變量”,編譯器是以“數(shù)據(jù)”為中心進行設(shè)計的。每個“變量”的每次寫入,都生成了一個新的數(shù)據(jù)版本,編譯器的優(yōu)化是圍繞數(shù)據(jù)版本展開的。接下來我們用如下的C語言代碼來解釋這一思想。

 

 

 

 

 

 

上圖(左)展示了一段簡單的C代碼,上圖(右)是這段代碼的SSA版本,也就是“編譯器眼中的代碼”。在C語言中,我們知道數(shù)據(jù)都是用變量來存儲的,因此數(shù)據(jù)操作的核心是變量,開發(fā)者需要關(guān)心變量的生存時間、何時被賦值、何時被使用。但是編譯器只關(guān)心數(shù)據(jù)的流向,因此每次賦值操作都會生成一個新的左值。例如左邊代碼只有一個a, 但是在右邊的代碼有4個變量,因為a里面的數(shù)據(jù)一共有4個版本。除了每次賦值操作會生成一個新的變量,最后的一個phi節(jié)點會生成一個新的變量。在SSA中,每個變量都代表數(shù)據(jù)的一個版本。也就是說,高級語言以變量為核心,而SSA格式以數(shù)據(jù)為核心。SSA中每次賦值操作都會生成一個版本的數(shù)據(jù),因此在寫IR的時候,時刻牢記IR的變量和高層語言不同,一個IR的變量代表數(shù)據(jù)的一個版本。Phi節(jié)點是SSA中的一個重要概念。在這個例子當中,a_4的取值取決于之前執(zhí)行了哪個分支,如果執(zhí)行了第一個分支,那么a_4 = a_1, 依次類推。Phi節(jié)點通過判斷這段代碼是從哪個Basic Block跳轉(zhuǎn)而來,選擇合適的數(shù)據(jù)版本。LLVM IR自然也是需要開發(fā)者寫Phi節(jié)點的,在循環(huán)、條件分支跳轉(zhuǎn)的地方,往往需要手寫很多phi節(jié)點,這是寫LLVM IR時邏輯上比較難處理的地方。

2.2 學會使用LLVM IR寫程序

熟悉LLVM IR最好的辦法就是使用IR寫幾個程序。在開始寫之前,建議先花30分鐘-1個小時再粗略閱讀下官方手冊(

https:// llvm.org/docs/LangRef.h tml ),熟悉下都有哪些指令的類型。接下來我們通過兩個簡單的case熟悉下LLVM IR編程的全部流程。

下面是一個循環(huán)加法的函數(shù)片段。這個函數(shù)一共包含三個Basic Block,loop、loop_body和final。其中l(wèi)oop是整個函數(shù)的開始,loop_body是函數(shù)的循環(huán)體,final是函數(shù)的結(jié)尾。在第5行和第6行,我們使用phi節(jié)點來實現(xiàn)結(jié)果和循環(huán)變量。

  1. define i32 @ir_loopadd_phi(i32*, i32){ 
  2.   br label %loop 
  3.        
  4. loop: 
  5.   %i = phi i32 [0,%2], [%newi,%loop_body] 
  6.   %res = phi i32[0,%2], [%new_res, %loop_body] 
  7.   %break_flag = icmp sge i32 %i, %1 
  8.   br i1 %break_flag, label %final, label %loop_body  
  9.        
  10. loop_body: 
  11.   %addr = getelementptr inbounds i32, i32* %0, i32 %i 
  12.   %val = load i32, i32* %addr, align 4 
  13.   %new_res = add i32 %res, %val 
  14.   %newi = add i32 %i, 1 
  15.   br label %loop 
  16.  
  17. final
  18.   ret i32 %res; 

下面是一個數(shù)組冒泡排序的函數(shù)片段。這個函數(shù)包含兩個循環(huán)體。LLVM IR實現(xiàn)循環(huán)本身就比較復雜,兩個循環(huán)嵌套會更加復雜。如果能夠用LLVM IR實現(xiàn)一個冒泡算法,基本上就理解了LLVM的整個邏輯了。

  1. define void @ir_bubble(i32*, i32) { 
  2.   %r_flag_addr = alloca i32, align 4 
  3.   %j = alloca i32, align 4 
  4.   %r_flag_ini = add i32 %1, -1 
  5.   store i32 %r_flag_ini, i32* %r_flag_addr, align 4 
  6.   br label %out_loop_head 
  7. out_loop_head: 
  8.   ;check break 
  9.   store i32 0, i32* %j, align 4 
  10.   %tmp_r_flag = load i32, i32* %r_flag_addr, align 4 
  11.   %out_break_flag = icmp sle i32 %tmp_r_flag, 0 
  12.   br i1 %out_break_flag, label %final, label %in_loop_head 
  13.   in_loop_head: 
  14.     ;check break 
  15.     %tmpj_1 = load i32, i32* %j, align 4 
  16.     %in_break_flag = icmp sge i32 %tmpj_1, %tmp_r_flag 
  17.     br i1 %in_break_flag, label %out_loop_tail, label %in_loop_body 
  18.   in_loop_body: 
  19.     ;read & swap 
  20.     %tmpj_left = load i32, i32* %j, align 4 
  21.     %tmpj_right = add i32 %tmpj_left, 1 
  22.     %left_addr = getelementptr inbounds i32, i32* %0, i32 %tmpj_left 
  23.     %right_addr = getelementptr inbounds i32, i32* %0, i32 %tmpj_right 
  24.     %left_val = load i32, i32* %left_addr, align 4 
  25.     %right_val = load i32, i32* %right_addr, align 4 
  26.     ;swap check 
  27.     %swap_flag = icmp sge i32 %left_val, %right_val 
  28.     %left_res  = select i1 %swap_flag, i32 %right_val, i32 %left_val  
  29.     %right_res = select i1 %swap_flag, i32 %left_val, i32 %right_val 
  30.     store i32 %left_res, i32* %left_addr, align 4 
  31.     store i32 %right_res, i32* %right_addr, align 4 
  32.     br label %in_loop_end 
  33.   in_loop_end: 
  34.     ;update j 
  35.     %tmpj_2 = load i32, i32* %j, align 4 
  36.     %newj = add i32 %tmpj_2, 1 
  37.     store i32 %newj, i32* %j, align 4 
  38.     br label %in_loop_head 
  39. out_loop_tail: 
  40.   ;update r_flag  
  41.   %tmp_r_flag_1 = load i32, i32* %r_flag_addr, align 4 
  42.   %new_r_flag = sub i32 %tmp_r_flag_1, 1 
  43.   store i32 %new_r_flag, i32* %r_flag_addr, align 4 
  44.   br label %out_loop_head 
  45. final
  46.   ret void 

我們把如上的LLVM IR用clang編譯器編譯成object文件,然后和C語言寫的程序鏈接到一起,即可正常調(diào)用。在上面提到的case中,我們只使用了i32、i64等基本數(shù)據(jù)類型,LLVM IR中支持struct等高級數(shù)據(jù)類型,可以實現(xiàn)更為復雜的功能。

2.3 使用LLVM API實現(xiàn)Codegen

編譯器本質(zhì)上就是調(diào)用各種各樣的API,根據(jù)輸入去生成對應(yīng)的代碼,LLVM Codegen也不例外。在LLVM內(nèi)部,一個函數(shù)是一個class,一個Basic Block試一個class, 一條指令、一個變量都是一個class。用LLVM API實現(xiàn)codegen就是根據(jù)需求,用LLVM內(nèi)部的數(shù)據(jù)結(jié)構(gòu)去實現(xiàn)相應(yīng)的IR。

  1. Value *constant = Builder.getInt32(16); 
  2.     Value *Arg1 = fooFunc->arg_begin(); 
  3.     Value *val = createArith(Builder, Arg1, constant); 
  4.  
  5.     Value *val2 = Builder.getInt32(100); 
  6.     Value *Compare = Builder.CreateICmpULT(val, val2, "cmptmp"); 
  7.     Value *Condition = Builder.CreateICmpNE(Compare, Builder.getInt1(0), "ifcond"); 
  8.  
  9.     ValList VL; 
  10.     VL.push_back(Condition); 
  11.     VL.push_back(Arg1); 
  12.  
  13.     BasicBlock *ThenBB = createBB(fooFunc, "then"); 
  14.     BasicBlock *ElseBB = createBB(fooFunc, "else"); 
  15.     BasicBlock *MergeBB = createBB(fooFunc, "ifcont"); 
  16.     BBList List; 
  17.     List.push_back(ThenBB); 
  18.     List.push_back(ElseBB); 
  19.     List.push_back(MergeBB); 
  20.  
  21.     Value *v = createIfElse(Builder, List, VL); 

如上是一個用LLVM API實現(xiàn)codegen的例子。其實這就是個用C++寫IR的過程,如果知道如何寫IR的話,只需要熟悉下這套API就可以了。這套API提供了一些基本的數(shù)據(jù)結(jié)構(gòu),比如指令、函數(shù)、基本塊、llvm builder等,然后我們只需要調(diào)用相應(yīng)的函數(shù)去生成這些對象即可。一般來說,首先我們先生成函數(shù)的原型,包括函數(shù)名字、參數(shù)列表、返回類型等。然后我們在根據(jù)函數(shù)的功能,確定都需要有哪些Basic Block以及Basic Block之間的跳轉(zhuǎn)關(guān)系,然后生成相應(yīng)的Basic。最后我們再按照一定的順序去給每個Basic Block填充指令。邏輯是,這個流程和用LLVM IR寫代碼是相仿的。

3. Codegen技術(shù)分析

如果我們用上文所描述的方法,生成一些簡單的函數(shù),并且用C寫出對應(yīng)的版本進行性能對比,我們就會發(fā)現(xiàn),LLVM IR的性能并不會比C快。一方面,計算機底層執(zhí)行的是匯編,C語言本身和匯編是非常接近的,了解底層的程序員往往能夠從C代碼中推測出大概會生成什么樣的匯編。另一方面,現(xiàn)代編譯器往往做了很多優(yōu)化,一些大大減輕了程序員的優(yōu)化負擔。因此,使用LLVM IR進行Codegen并不會獲得比手寫C更好的性能,而且使用LLVM Codegen有一些明顯的缺點。想要真正用好LLVM,我們還需要熟悉LLVM的特點。

3.1 缺點分析

缺點1:開發(fā)難。 實際開發(fā)中幾乎不會有工程使用匯編作為主要開發(fā)語言,因為開發(fā)難度太大了,有興趣的小伙伴可以試著寫個快排感受一下。即使是數(shù)據(jù)庫、操作系統(tǒng)這樣的基礎(chǔ)軟件,往往也只是在少數(shù)的地方會用到匯編。使用LLVM IR開發(fā)會有類似的問題。比如上文展示的最復雜例子是冒泡算法。開發(fā)者用C寫個冒泡只需要幾分鐘,但是用LLVM IR寫個冒泡可能要一個小時。另外,LLVM IR很難處理復雜的數(shù)據(jù)結(jié)構(gòu),比如結(jié)構(gòu)體、類。除了LLVM IR中的那些基本數(shù)據(jù)結(jié)構(gòu)外,新增一個復雜的數(shù)據(jù)結(jié)構(gòu)非常難。因此在實際的開發(fā)當中,采用Codegen會導致開發(fā)難度指數(shù)級上升。

缺點2:調(diào)試難 。開發(fā)者通常通過單步跟蹤的方式去調(diào)試代碼,但是LLVM IR是不支持的。一旦代碼出問題,只能是人肉一遍一遍看LLVM IR。如果懂匯編的話,可以通過單步跟蹤生成的匯編進行調(diào)試,但是匯編語言和IR之間并不是簡單的映射關(guān)系,因此只能一定程度上降低調(diào)試難度,并不完全解決調(diào)試的問題。

缺點3: 運行成本 。生成LLVM IR往往很快,但是生成的IR需要調(diào)用LLVM 中的工具進行優(yōu)化、以及編譯成二進制文件,這個過程是需要時間的(請聯(lián)想一下GCC編譯的速度)。在數(shù)據(jù)庫的開發(fā)過程中,我們的經(jīng)驗值是每個函數(shù)大約需要10ms-100ms的codegen成本。大部分的時間花在了優(yōu)化IR和IR到匯編這兩步。

3.2 適用場景

了解了LLVM Codegen的缺點,我們才能去分析其優(yōu)點、選擇合適場景。下面這部分是團隊在開發(fā)過程中總結(jié)的適合使用LLVM Codegen的場景。

場景1:Java/python等語言 。上文中提到過LLVM IR并不會比C快,但是會比Java/python等語言快啊。例如在Java中,有時候為了提升性能,會通過JNI調(diào)用一些C的函數(shù)提升性能。同理,Java也可以調(diào)用LLVM IR生成的函數(shù)提升性能。

場景2:硬件和語言不兼容 。LLVM支持多種后端,比如X86、ARM和GPU。對于一些硬件與語言不兼容的場景,可以利用LLVM實現(xiàn)兼容。例如如果我們的系統(tǒng)是用Java語言開發(fā)、想要調(diào)用GPU,可以考慮用LLVM IR生成GPU代碼,然后通過JNI的方法進行調(diào)用。這套方案不僅支持NVIDIA的GPU,也支持AMD的GPU,而且對應(yīng)生成的IR也可以在CPU上執(zhí)行。

場景3:邏輯簡化 。以數(shù)據(jù)庫為例,數(shù)據(jù)庫執(zhí)行引擎在執(zhí)行過程中需要做大量的數(shù)據(jù)類型、算法邏輯相關(guān)的判斷。這主要是由于SQL中的數(shù)據(jù)類型和邏輯,很多是在數(shù)據(jù)庫開發(fā)時無法確定的,只能在運行時決定。這一部分過程,也被稱為“解釋執(zhí)行”。我們可以利用LLVM在運行時生成代碼,由于這個時候數(shù)據(jù)類型和邏輯已經(jīng)確定,我們可以在LLVM IR中刪除那些不必要的判斷操作,從而實現(xiàn)性能的提升。

4. LLVM在數(shù)據(jù)庫中的應(yīng)用

在數(shù)據(jù)庫當中,團隊是用LLVM來進行表達式的處理,接下來我們以PostgreSQL數(shù)據(jù)庫和云原生數(shù)據(jù)倉庫AnalyticDB PostgreSQL為對比,解釋LLVM的應(yīng)用方法。

PostgreSQL為了實現(xiàn)表達式的解釋執(zhí)行,采用了一套“拼函數(shù)”的方案。PostgreSQL中實現(xiàn)了大量C函數(shù),比如加減法、大小比較等,不同類型的都有。SQL在生成執(zhí)行計劃階段會根據(jù)表達式符號的類型和數(shù)據(jù)類型選擇相應(yīng)的函數(shù)、把指針存下來,等執(zhí)行的時候再調(diào)用。因此對于 "a > 10 and b < 5"這樣的過濾條件,假設(shè)a和b都是int32,PostgreSQL實際上調(diào)用了“Int8AndOp(Int32GT(a, 10), Int32LT(b, 5))”這樣一個函數(shù)組合,就像搭積木一樣。這樣的方案有兩個明顯的性能問題。一方面這種方案會帶來比較多次數(shù)的函數(shù)調(diào)用,函數(shù)調(diào)用本身是有成本的。另一方面,這種方案必須要實現(xiàn)一個統(tǒng)一的函數(shù)接口,函數(shù)內(nèi)部和外部都需要做一些類型轉(zhuǎn)換,這也是額外的性能開銷。Odyssey使用LLVM 進行codegen,可以實現(xiàn)最小化的代碼。因為在SQL下發(fā)以后,數(shù)據(jù)庫是知道表達式的符號和輸入數(shù)據(jù)的類型的,因此只需要根據(jù)需求選取相應(yīng)的IR指令就可以了。因此只需要三條IR指令,就可以實現(xiàn)這個表達式,然后我們把表達式封裝成一個函數(shù),就可以在執(zhí)行的時候調(diào)用了。這次操作,把多次函數(shù)調(diào)用簡化成了一次函數(shù)調(diào)用,大大減少了指令的總數(shù)量。

  1. // 樣例SQL 
  2. select count(*) from table where a > 10 and b < 5
  3.  
  4. // PostgreSQL解釋執(zhí)行方案:多次函數(shù)調(diào)用 
  5. result = Int8AndOp(Int32GT(a, 10), Int32LT(b, 5)); 
  6.  
  7. // AnalyticDB PostgreSQL方案:使用LLVM codegen生成最小化底層代碼 
  8. %res1 = icmp ugt i32 %a, 10
  9. %res2 = icmp ult i32 %b, 5;  
  10. %res = and i8 %res1, %res2; 

在數(shù)據(jù)庫中,表達式主要出現(xiàn)在幾個場景。一類是過濾條件,通常出現(xiàn)在where條件中。一類是輸出列表,一般跟在select之后。有些算子,比如join、agg等,它的判斷條件中也可能會出現(xiàn)一些比較復雜的表達式。因此表達式的處理是會出現(xiàn)在數(shù)據(jù)庫執(zhí)行引擎的各個模塊的。在AnalyticDB PostgreSQL版中,開發(fā)團隊抽象出了一個表達式處理框架,通過LLVM Codegen來處理這些表達式,從而提高了執(zhí)行引擎的整體性能。

 

 

 

 

 

 

5. 總結(jié)

LLVM作為一個流行的開源編譯框架,近年來被用于數(shù)據(jù)庫、AI等系統(tǒng)的性能加速。由于編譯器理論本身門檻較高,因此LLVM的學習有一定的難度。而且從工程上,還需要對LLVM的工程特點和性能特征有比較準確的理解,才能找到合適的加速場景。阿里云數(shù)據(jù)庫團隊的云原生數(shù)據(jù)倉庫產(chǎn)品AnalyticDB PostgreSQL版基于LLVM實現(xiàn)了一套運行時的表達式處理框架,能夠有效地提高系統(tǒng)在進行復雜數(shù)據(jù)分析時地性能。

 

責任編輯:張燕妮 來源: 知乎
相關(guān)推薦

2021-06-28 09:26:51

數(shù)據(jù)庫LLVM

2009-10-27 16:36:07

Oracle如何解鎖

2024-11-13 15:15:46

2009-07-22 11:45:43

2023-03-03 08:00:00

重采樣數(shù)據(jù)集

2011-05-19 10:29:40

數(shù)據(jù)庫查詢

2011-04-12 13:44:17

CachéOracle數(shù)據(jù)庫

2014-06-10 15:07:19

Oracle數(shù)據(jù)庫優(yōu)化

2018-05-17 23:07:12

2011-03-04 10:03:45

EJB數(shù)據(jù)庫應(yīng)用

2010-10-09 10:29:29

MySQL外鍵

2011-04-02 14:50:58

數(shù)據(jù)庫代碼

2011-05-18 09:39:19

Oracle數(shù)據(jù)庫性能優(yōu)化

2009-03-19 08:56:58

pureXMLDB2數(shù)據(jù)結(jié)構(gòu)

2011-05-17 15:02:15

ORACLE數(shù)據(jù)庫備份

2023-03-07 16:21:26

2010-04-09 16:51:24

Oracle數(shù)據(jù)庫

2011-08-17 17:29:32

Windows編譯MySQL

2024-02-04 09:41:51

人工智能

2010-04-07 14:22:46

點贊
收藏

51CTO技術(shù)棧公眾號

日本中文字幕在线观看视频| 古装做爰无遮挡三级聊斋艳谭| 人人妻人人澡人人爽精品日本| 激情一区二区| 亚洲福利视频在线| 无码人妻丰满熟妇区96| 久久久久久女乱国产| 日韩精品91亚洲二区在线观看| 一二美女精品欧洲| 日本不卡一区二区在线观看| av在线免费播放| 成人99免费视频| 国产成人精品在线观看| 秋霞欧美一区二区三区视频免费| 亚洲一区二区av| 亚洲国产视频网站| 欧美日韩一区在线播放| 国产一区二区在线视频聊天| 午夜精品亚洲| 亚洲欧美国产日韩中文字幕| 17c国产在线| 波多野结衣中文在线| 久久精品一区二区三区不卡| 91久久久久久久久| 日韩高清精品免费观看| 成人在线丰满少妇av| 欧美性猛片aaaaaaa做受| 欧美 日韩 国产精品| 国产免费av高清在线| 国产精品亚洲综合一区在线观看| 2019中文字幕在线| 欧美h片在线观看| 亚洲黄页网站| 日韩三级精品电影久久久| 日韩视频在线免费看| 人妖欧美1区| 欧美国产激情二区三区| 国产精品午夜av在线| 又骚又黄的视频| 午夜在线精品偷拍| 久久久久国产精品一区| 国产精品69久久久久孕妇欧美| 久久午夜影院| 欧美一激情一区二区三区| 日本a在线免费观看| 顶级网黄在线播放| 久久亚洲私人国产精品va媚药| 91精品久久久久久综合乱菊| 亚洲高清毛片一区二区| 欧美不卡视频| 亚洲午夜久久久久久久| 三上悠亚 电影| 91精品亚洲一区在线观看| 精品高清一区二区三区| 黄色一级视频播放| 日本一区二区三区在线观看视频| 久草热8精品视频在线观看| 日韩免费观看高清| www.av免费| 三区四区不卡| 在线观看精品国产视频| 免费一级做a爰片久久毛片潮| 麻豆成人入口| 亚洲黄色片网站| 中文字幕天堂av| 日韩欧美另类中文字幕| 日韩亚洲欧美在线观看| 1314成人网| 精品国产一级| 日韩欧美一区中文| 91人妻一区二区三区| 99精品视频在线免费播放| 欧美三级视频在线观看| 制服丝袜综合网| 久久亚洲人体| 在线电影欧美成精品| 久久久精品高清| 伊人国产精品| 91精品国产手机| 久久黄色一级视频| 911精品国产| 亚洲国产91精品在线观看| 亚洲黄色小说在线观看| 国产精品丝袜在线播放| 日韩成人在线免费观看| 国精品无码人妻一区二区三区| 亚洲区小说区| 中文字幕欧美日韩| 青青青在线免费观看| 国内在线观看一区二区三区| 高清欧美性猛交xxxx| 精品在线播放视频| 久久久噜噜噜| 国产精品中文字幕久久久| 91禁在线观看| 成人性视频免费网站| 精品无人区一区二区三区 | 91精品观看| 欧美裸体男粗大视频在线观看| 在线免费观看一区二区三区| 大乳在线免费观看| 国产精品三级视频| 日本天堂免费a| 男人av在线播放| 欧亚一区二区三区| www.com久久久| jizz18欧美18| 一色桃子一区二区| 欧美三级 欧美一级| 国产精品美女久久久| 国产精品爽黄69天堂a| www.我爱av| 久久久精品中文字幕麻豆发布| 艳色歌舞团一区二区三区| 金瓶狂野欧美性猛交xxxx| 欧美日韩亚洲一区二区| 国产3p在线播放| 婷婷成人影院| 中文字幕日韩高清| 精品无码免费视频| 麻豆精品视频在线观看| 久久99导航| 黄色免费网站在线| 91福利国产精品| 久久精品aⅴ无码中文字字幕重口| 久久av综合| 久久久久久12| 亚洲午夜激情视频| 91麻豆国产香蕉久久精品| 特级黄色录像片| 另类专区亚洲| 亚洲国产成人精品女人久久久 | 日韩精品一区二区三区色欲av| 欧美经典影片视频网站| 国产午夜精品视频免费不卡69堂| 欧美精品久久久久性色| 日本欧美加勒比视频| 国产精品jizz视频| 免费不卡视频| 欧美亚洲日本一区| 欧美丰满少妇人妻精品| 欧美视频一区| 91影视免费在线观看| 国产裸舞福利在线视频合集| 亚洲成人7777| 又黄又爽又色的视频| 99国产精品一区二区| 日本高清视频一区| 欧美一级做性受免费大片免费| 国产精品久久久久aaaa| 黄色免费网址大全| 中文有码一区| 97视频免费在线看| 成人午夜视频一区二区播放| 亚洲欧美日韩国产成人精品影院 | 黑人巨大精品欧美黑白配亚洲| 欧美伦理一区二区| 超碰一区二区| 亚洲男人天堂视频| www日韩精品| 成人免费观看av| 男人天堂新网址| 日韩第一区第二区| 欧美日韩高清区| 草逼视频免费看| 亚洲精品ww久久久久久p站| 韩国视频一区二区三区| 四虎影视精品| 日本道色综合久久影院| 欧洲一区av| 欧美吞精做爰啪啪高潮| 亚洲欧美综合7777色婷婷| 奇米888四色在线精品| 亚洲国产精品一区在线观看不卡| 无人区在线高清完整免费版 一区二| 亚洲欧美中文在线视频| 亚洲黄网在线观看| 中文字幕乱码日本亚洲一区二区| 亚洲 中文字幕 日韩 无码| 婷婷综合成人| 国产91精品久久久久久| 神马久久精品| 欧美丝袜第三区| 欧美性生交大片| 激情综合五月天| 中文字幕日韩精品一区二区| 亚洲男男av| 欧美激情奇米色| 亚洲av片在线观看| 欧美一a一片一级一片| 亚洲熟女少妇一区二区| 国产成人av在线影院| 福利视频一二区| 成人无号精品一区二区三区| 亚洲自拍欧美色图| 多野结衣av一区| 一本一道久久a久久精品逆3p| 国产v片在线观看| 精品动漫一区二区| 国产白丝一区二区三区| 国产91丝袜在线播放| 99蜜桃臀久久久欧美精品网站| 久久亚洲国产| 国产偷久久久精品专区| av在线不卡精品| 欧美国产日韩一区二区三区| 欧美日韩国产综合视频| 欧美久久婷婷综合色| 国产福利拍拍拍| 中文字幕一区二区三区视频| 久久久久久婷婷| 六月婷婷色综合| 免费无码毛片一区二三区| 日本一区二区高清不卡| 国产美女精品久久久| 国产精品亲子伦av一区二区三区| 久久久久久国产精品三级玉女聊斋 | 亚洲国产日韩a在线播放性色| 能免费看av的网站| 国产剧情一区在线| 四虎永久在线精品无码视频| 88国产精品视频一区二区三区| 久久国产主播精品| 精品中文在线| 国产欧美日韩精品在线观看| 超级白嫩亚洲国产第一| 久久躁狠狠躁夜夜爽| 国产资源在线播放| 亚洲国产精品va在线| 国产女18毛片多18精品| 欧美午夜电影网| 免费看日批视频| 香蕉久久一区二区不卡无毒影院| 天天做夜夜爱爱爱| 国产网红主播福利一区二区| jjzz黄色片| 日韩成人精品在线| 日韩精品视频一区二区在线观看| 久久精品播放| 日韩精品久久一区二区三区| 日韩免费一级| 国产精品久久电影观看| 免费h在线看| 欧美乱妇高清无乱码| 欧美在线一卡| 亚洲黄色在线看| 乱色精品无码一区二区国产盗| 欧美日韩在线三区| 黄色片视频免费| 欧美性猛交xxxx富婆| 精品少妇一二三区| 亚洲高清免费观看高清完整版在线观看| 国产福利视频网站| 日韩美女视频一区| 黄色一级大片在线免费观看| 欧美激情在线看| 国产精品免费无码| 亚洲国产精品精华液2区45| 日韩精品电影一区二区| 久久综合给合久久狠狠狠97色69| 好男人香蕉影院| 91污片在线观看| 亚洲永久精品ww.7491进入| ww亚洲ww在线观看国产| 精品少妇一区二区三区免费观| 99麻豆久久久国产精品免费优播| 完美搭档在线观看| 成人动漫一区二区| 你懂的在线观看网站| 成人av网站在线| wwwwww日本| 欧美国产日韩精品免费观看| 国产视频三区四区| 国产精品久久久久久久久免费樱桃| 欧美午夜激情影院| 综合欧美一区二区三区| 极品久久久久久| 亚洲一区二区三区国产| 日本少妇在线观看| 亚洲国产aⅴ成人精品无吗| 精品无码人妻一区二区三区| 精品久久久久久电影| 国产亚洲欧美在线精品| 在线观看网站黄不卡| 国产免费a视频| 欧美精品久久一区二区三区| 国产浮力第一页| 亚洲国内高清视频| 国产高清免费av在线| 搡老女人一区二区三区视频tv| 色帝国亚洲欧美在线| 午夜精品在线视频| 成人午夜在线| 18成人在线| 亚洲美女久久| 一本二本三本亚洲码| 亚洲婷婷在线| 九热视频在线观看| 国产成人综合亚洲网站| 人妻丰满熟妇aⅴ无码| 国产日本欧洲亚洲| 黄色一级片中国| 精品色蜜蜜精品视频在线观看| 国产黄色免费视频| 日韩欧美资源站| 免费人成在线观看网站| 超薄丝袜一区二区| 国偷自产一区二区免费视频| 91色精品视频在线| 亚洲人成精品久久久| 亚洲av综合色区| 久久亚洲一区| 91成人在线观看喷潮蘑菇| 中文字幕精品综合| 色婷婷av国产精品| 欧美一级片在线| 九色视频在线播放| 欧美夫妻性生活xx| 国产精品99精品一区二区三区∴| 大波视频国产精品久久| 欧美电影《轻佻寡妇》| 欧美s码亚洲码精品m码| 国产乱淫av一区二区三区 | 国产日产欧美一区二区视频| 麻豆亚洲av熟女国产一区二| 欧美在线播放高清精品| 婷婷在线免费视频| 欧美另类老女人| 国产成人77亚洲精品www| 久久av免费一区| 国产真实久久| 国产区二区三区| www..com久久爱| 久久福利免费视频| 亚洲www啪成人一区二区麻豆| 国产强伦人妻毛片| 国产视频欧美视频| 怡红院av在线| 成人激情免费在线| heyzo久久| 精品久久久久av| 91啪九色porn原创视频在线观看| 国产性生活网站| 日韩欧美一区二区免费| 中日韩高清电影网| 成人国产精品久久久| 成人女性视频| 国产精品一区二区小说| 国产女人水真多18毛片18精品视频 | 国产女人18毛片水18精| 日韩在线视频观看| 巨大黑人极品videos精品| 神马影院一区二区三区| 久久精品一区二区国产| 国产麻豆天美果冻无码视频 | 国产精品国模大尺度私拍| 自拍偷拍欧美| 亚洲午夜精品在线观看| 亚洲综合男人的天堂| 午夜精品久久久久久久99老熟妇 | 精品视频免费看| 在线免费看黄网站| 成人a在线视频| 91成人超碰| 国产吃瓜黑料一区二区| 一区二区成人在线视频| 老牛影视av牛牛影视av| 992tv在线成人免费观看| 天堂资源在线亚洲| 日日摸天天爽天天爽视频| 日本一区二区三区四区| 亚洲一区二区视频在线播放| 久久久国产精品x99av| 久久久久亚洲精品中文字幕| 好吊色视频988gao在线观看| 高清av一区二区| 亚洲精品77777| 亚洲人午夜精品| 一区二区三区| 日本中文字幕在线视频观看| 国产成人av电影免费在线观看| 免费三级在线观看| 欧美一区2区视频在线观看| 污污的网站在线看| 国产精品一区视频| 国产精品久久久久9999高清| av网站免费在线播放| 色呦呦网站一区| 婷婷成人激情| 91传媒免费看| 亚洲国产国产亚洲一二三| 中文字幕日韩三级片| 色哟哟欧美精品| 欧美日韩在线资源| 国产精品久久7| 国产一区导航| 日本伦理一区二区三区| 日韩电影视频免费| 在线天堂资源www在线污| 天天综合狠狠精品|