數據流分析之WorkList Algorithm

目錄

 

(1)如何求解數據流方程?

(2)WorkList Algorithm


(1)如何求解數據流方程?

不論是Reaching Definition Analysis中對可達定義集合的求解,還是Liveness Analysis中對活躍變量集合的求解,本質上都是在解方程。

以RDA舉例,其數據流方程如下:

\large IN(p) = \cup OUT(p_s),p_s\in pred(p) \ (1) \\OUT(p)=(IN(p)- defs(v))\cup \{(p,v)\} \ (2)

可認爲每個指令都對應方程中的兩個變量,即IN(p)和OUT(p)。爲了減少變量個數,把(1)式帶入(2)式,以去掉IN(p):

\large OUT(p)=(\cup OUT(p_s)- defs(v))\cup \{(p,v)\} ,p_s\in pred(p)

此時方程中的變量爲\large OUT(p),p \in S_{instruction},而\large defs(v)\large \{(p,v)\}則屬於常數,因爲其值隨着指令的確定而相應確定。

此外,方程還有一個初值,即,

\large IN(first\ program\ point) =\{\ \}

轉化爲OUT,

\large OUT(first\ program\ point) =\{something\}

 

爲了說明求解思路,先用更簡化的符號來表示上述方程:

\large y_1 = c \ (1)\\ y_2 = f_2(y_1,y_2,...,y_n) \ (2)\\ ...\\ y_n= f_n(y_1,y_2,...,y_n) \ (n)

通過此方程可以看出,數據流方程的一個重要特點就是,待求的每個未知數既是若干方程的自變量,也是某個方程的因變量。


從此特點出發,我們很快發現一種求解的思路,即先給定一組未知數的初始值如\large \{y_1^0,y_2^0,...,y_n^0\},接着將這組值帶入上述方程,得到又一組未知數的值\large \{y_1^1,y_2^1,...,y_n^1\},如果\large \{y_1^0,y_2^0,...,y_n^0\}\large \{y_1^1,y_2^1,...,y_n^1\}相等,則說明找到了一組方程的解,因爲這組值可讓上述方程成立。如果\large \{y_1^0,y_2^0,...,y_n^0\}\large \{y_1^1,y_2^1,...,y_n^1\}不相等,則重複上述過程,一定能找出方程的一組解。原因如下:

 

對於RDA,自變量\large OUT(p_s),p_s\in pred(p)越大(即集合的基數越大),根據方程\large OUT(p)=(\cup OUT(p_s)- defs(v))\cup \{(p,v)\} ,p_s\in pred(p),其因變量\large OUT(p)也相應越大。

由此可知,上述方程中的函數\large f_1,f_2,...f_n都是單調不減的,即如果\large \{y_1^{k+1},y_2^{k+1},...,y_n^{k+1}\}\geq \{y_1^{k},y_2^{k},...,y_n^{k}\},則有

\large f(y_1^{k+1},y_2^{k+1},...,y_n^{k+1})\geq f(y_1^{k},y_2^{k},...,y_n^{k}),即

\large \{y_1^{k+2},y_2^{k+2},...,y_n^{k+2}\}\geq \{y_1^{k+1},y_2^{k+1},...,y_n^{k+1}\}

要讓解集合\large \{y_1^{i},y_2^{i},...,y_n^{i}\}隨着迭代的進行而越來越大(即集合的基數越大),還需要一個初始條件,即

\large \{y_1^1,y_2^1,...,y_n^1\}\geq \{y_1^0,y_2^0,...,y_n^0\}

如果令\large \{y_1^0,y_2^0,...,y_n^0\}=\{\{\ \},\{\ \},...,\{\ \}\},則有

\large \{y_1^1,y_2^1,...,y_n^1\}\geq \{\{\ \},\{\ \},...,\{\ \}\}=\{y_1^0,y_2^0,...,y_n^0\}

此時初始條件和函數單調性共同作用,有如下鏈式反應:

\large \{y_1^{k+1},y_2^{k+1},...,y_n^{k+1}\}\geq \{y_1^{k},y_2^{k},...,y_n^{k}\}\geq...\geq\{\{\ \},\{\ \},...,\{\ \}\}

由於\large y_1,y_2,...y_n是離散值(集合)且有上界(集合元素有上限),因此上述鏈式反應一定會終止,終止時會有

\large \{y_1^{i+1},y_2^{i+1},...,y_n^{i+1}\}= \{y_1^{i},y_2^{i},...,y_n^{i}\},這即爲方程的一組解。

 

(2)WorkList Algorithm

上述思路對應的算法爲Round-Robin Iterations,即各未知數的迭代次數(or更新次數)保持同步,即算法每次循環結束後都有

\large \{y_1^k,y_2^k,...,y_n^k\},而WorkList Algorithm則不同,其未知數的迭代次數不一定同步,在算法每次循環結束後可能會出現

\large \{y_1^{k+5},y_2^{k+1},...,y_i^k,...,y_n^{k-2}\},這說明針對未知數的值的更新,WorkList Algorithm有一套優先級規則。(其實這兩種更新思路與數值分析中求解線性方程組的Jacobi迭代和Gauss-Seidel迭代有共通之處)

 

先給出WorkList Algorithm的(不規範的)僞代碼:

WorkList()
    for i <- 1 to n do
        y[i] <- { } //初始化隨具體情況而定
    w <- [ y[1] y[2] ... y[n] ] //將未知數放入worklist中
    while(!is_empty(w)) do 
        y[i] <- extract(w) //從worklist以某種方式抽出一個未知數
        old <- y[i] //記錄此未知數的值
        y[i] <- f_i(y[1], y[2], ..., y[n]) //挑出以此未知數作爲因變量的方程,並進行運算,結果賦給此未知數
        if old != y[i] then //如果未知數的值在運算後發生變化
            for y[k] <- dep(y[i]) do 
            //將依賴它的那些未知數放入worklist中,a依賴b的含義是
            //以a爲因變量的方程使用b作爲自變量,因此當b發生變化,a也就可能發生變化
            //故把a放入worklist中
                w <- insert(w, y[k])
        

未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章