• 沒有找到結果。

藉由 dependent path set 選取測試單元 concurrent path

經上一階段的處理,已得到一些有依存關係的 path 組合,每一 path 組合為 一 dependent path set。一個 dependent path set 的 path 均屬不同 thread。

本階段則是利用使用這些有依存關係的 path 組合以及沒有呼叫 shared object 的 independent path 以組合產生最少數目的 concurrent path 來建構一條 main() 的 path 應測試的 concurrent paths。

一個 concurrent path 由參與 concurrent execution 的每一個 Run 之一條 path 所組成,前面所述的有依存關係的 path 組合,可能只包含部分 Run 的一條 path,

因此稱為一個 partial concurrent path。一個 partial concurrent pathP 為另一 partial 1 concurrent pathP 的子集合,則2 P 含有2 P 中所有的 Run,且這些 Run 的 path 均相1 同,則稱P 包含2 P 。 1

二個 partial concurrent pathP 與1 P 可以互相合併而共同執行,合併的條件是2 P 與1 P 中屬同一個 Run 的 path 均相同。若2 P 與1 P 中有相同的 Run,且2 P 與1 P 在2 此 Run 中之 path 是不同的,則無法合併成一個 partial concurrent path,我們稱此 partial concurrent pathsP 與1 P 互斥。 2

但參與 concurrent execution 的 Run 中有一些 path 並沒有存取任何 shared object,這些 path 稱為 independent path,這些 path 需被測試,因此可將 independent path 視 為 一 條 partial concurrent path , 因 此 本 階 段 的 目 的 是 由 這 些 partial concurrent paths 來產生一組最少個數的 concurrent paths,藉由這些 concurrent paths 的執行可驗證所有的 partial concurrent path 的正確性。

如圖3-17所示,一個 main()的 path 啟動了三個 Run:Run A、Run B 及 Run C,此一條 partial concurrent path A1B2 若要成為 concurrent path 尚缺少 Run C 的 path。選取 Run C 中 path C2 加入這個 partial concurrent path 則與 main()的 path 組合而成 concurrent path,測試此 concurrent path 即可保證原本的 partial concurrent path A1B2 會被測試。也可由 Run C 選擇 C1 path 而組成 concurrent path,但在

Run C 中選取 C2 較 C1 為佳,因為 C2 沒有存取任何 shared object,較不會對 shared object 產生副作用。

由上例可知,partial concurrent path set 的任一 partial concurrent path 均需被 測試,而一條 concurrent path 可能同時測試二個以上的 partial concurrent path,因 此如何挑選出可同時被測試的 partial concurrent path 組合是本階段的重點。

圖3-17 partial concurrent path A1B1 應與 C2 結合

若二條 partial concurrent path 是互斥,則無法同時被一條 concurrent path 測 試,因此可將這些 partial concurrent path 集合以 graph 表示,每一個 node 代表一 條 partial concurrent path,若二 partial concurrent paths 互斥,則在對應的 nodes 間建立一條 edge 以表示之,以 N 代表所有 partial concurrent path 所對應的 node 的集合,E代表各 partial concurrent paths 間互斥關係 edge 的集合,這組 partial concurrent path set 即可用 graphG=(N,E)來代表。由G 選出沒有 edge 相連的 nodes 形成 node partition,這些 nodes 所對應的 partial concurrent paths 即可合併 成一個新的 partial concurrent path 而同時測試。因此尋找最少組數的 partial concurrent path 的問題可視為將圖 G 切割為最少組數不含 edge 的 node partition。

將同一個 partition 的 nodes 著以同樣顏色,不同 partition 的顏色不重複,有 edge 相連的相鄰 node 都著上了不同顏色,形成圖論中 graph coloring 問題,因此

Run A Run B Run C

S1 S2

1 2 3 1 2 3 1 2

「尋找最少組合之可同時被測之 partial concurrent path set 組合」與「在 G 上找 出最少顏色的著色方法」的問題相等。在圖論中,graph coloring 問題的最佳著 色法已被證明為 NP-Completed 問題,換言之,對於一個現有的 partial concurrent path 集合,無法找出一個 polynomial time 運算時間的方法使其合併為最少數目之 兩兩互斥 partial concurrent path,因此只能找出一個有效的演算法,使其在有限 運算次數與時間內找出趨近於最佳解的方法。

為了實現這個方法,我們觀察 partial concurrent path 合併的性質。

Partial concurrent path set 中可以兩兩合併的對象可能有很多,一 partial concurrent path 也可能與多個其它 partial concurrent paths 可以結合,但每一次的 合併所產生的 partial concurrent path 勢必影響下一階段的合併動作之 partial concurrent path 選取,因此可選擇還可作更多組合的一組來合併;由一 partial concurrent path 的集合中選擇兩個 partial concurrent path 來結合,所產生的新 partial concurrent path set 的元素個數將比原來的集合少一,再由這個新的集合中 挑選兩個來結合,直到這集合中所有 partial concurrent path 皆兩兩互斥為止,因 此可採用 stage-by-stage 的方式,使其經過的 stage 愈多,則集合中的元素個數愈 少,代表最後所得之互斥 partial concurrent path 之數目愈少,愈有機會找出最佳 解。

每一個 stage 可作合併的 partial concurrent path 組合可能很多,應選擇可使 新組合有最多合併方式的那一種較為恰當,這樣能在下階段有更多機會進行合 併,較易使組合的 stage 之次數增多,因此可採用 gaming tree 之 look ahead 方式 來挑選當前最佳的結合方式,針對每一種合併方法,先產生下一階段其可能發生 的組合情況,並計算其可能的組合數,進而選出下階段可產生最多組合數的合併 方法,如圖3-18所示。

圖3-18 gamming tree 示意圖

當 partial concurrent path set 中任二 partial concurrent path 皆為互斥時,即對 每一個 partial concurrent path 分別產生可包含所有 Run 的 concurrent path,測試 這些 concurrent path,即可保證各個 independent path 及所有 shared object 的各種 組合情況皆可被測試。

若一 stage 有 N 個 partial concurrent path,有M種結合方式,則下一個 stage 將有N −1個 partial concurrent path,利用 look ahead 方法需一一比對這N−1個 partial concurrent path 兩兩是否可以合併;比對N−1個 partial concurrent path 有 多少合併組合需要C2N1 =(N −1)(N −2)次比對,時間複雜度為θ(N2);有M 個 候選結合,因此選出最佳走法所需之時間複雜度為θ(MN2),計算量非常龐大,

實有必要減少其計算量。若能由當前 stage 的狀態以少量計算推算出下一步驟較 有利的結合,而不必算出一個結合的評分,則可減少許多計算量。

假設一組 partial concurrent path set 中,二個 partial concurrent pathP 與1 P 可2 合併為 partial concurrent pathP',新產生的 partial concurrent path 集合比原 partial concurrent path 集合少了P 與1 P 而多出 '2 P , 'P 與此集合中其它任一 partial

當前盤面

…… 可能走法

可能盤面

……

可能走法

可能盤面

concurrent path 是否可合併可由P 與i P 及1 P 之關係推論如下列四種情形: 2

假設N 個 partial concurrent path 中有M 個組合情況,若二個 partial concurrent pathP 及1 P 已合併為 '2 P ,因P 與1 P 已不存在,故2 M 個組合將減少一,再由任一

P 與i P 及1 P 之關係,可看出對2 M 之影響。根據上述關係,可推論P 在新 partial i concurrent path 集合與其他 partial concurrent path 之合併數目可推論如下:

P 可與i P 結合 1 P 可與i P 結合 2 P 可與 'i P 結合 對新集合中可組

結合候選需要θ(MN)的時間複雜度,並且比對僅需對可結合矩陣進行查表動 作,較原本需要檢查每個 Run 是否有不同的 path 快上許多。在選擇了一個結合 之後,下一個 stage 所需的可結合方式以及可結合矩陣,也可以利用上表,從這 個 stage 的可結合方式以及可結合矩陣產生,只需O(N)的時間。

Partial concurrent path 的儲存方式如圖3-20所示,假設系統中存在有 RunA 至 RunN,則可使用一個陣列儲存 partial concurrent path 中的所有 path,陣列中 每一個 item 儲存這個 partial concurrent path 在每個 Run 所包含之 path 的 index,

例如在 RunA 的 item 中儲存 1 則表示這個 partial concurrent path 有 A1 這條 path。

倘若 partial concurrent path 不包含某個 Run 的 path,則儲存 0,如圖3-20 RunC 與 RunD 的 paths 皆未包含在 PCPi中。因為 partial concurrent path 最多只會在每 個 Run 含有一個 path,不會無限制的增長,因此使用陣列而不使用 linked-list,

可以省去配置記憶體的麻煩。

圖3-20 partial concurrent path 以陣列方式儲存

為了組合 partial concurrent path,因此在進行這個演算法之前會需要先產生 所有初始的 partial concurrent path,包括第一階段產生的 dependent path set 所組 成的 partial concurrent paths 與來自於 independent paths 的 partial concurrent paths。將這些 partial concurrent path 存在陣列Array 中,共有 N 個,作為這個運P 算方法的輸入資料。

為了快速比對兩 partial concurrent path 可否合併,第一個 stage 應將 N 個 partial concurrent path 實際兩兩比對,若可以合併,則將兩個 partial concurrent path 在陣列Array 中的索引儲存到陣列 C 中,並將這個組合在陣列 C 中的索引存在P

可結合矩陣A相對應的欄位裡,或是以-1 表示兩個 partial concurrent path 互斥不 併產生的 partial concurrent path 暫存使用。

後一個元素的方式快速進行。當所有 stage 結束後再為所有的 partial concurrent path 產生 concurrent path。所有處理的演算法如下所列:

TARGET:

組合partial concurrent path 並產生最後的 concurrent path IPNUT:

Array ArrayP; /* partial concurrent path set */

OUTPUT:

Array ArrayP; /* 最終的concurrent path set */

INTERMEDIATE DATA:

Integer N; /* N 為 partial concurrent path 的數量 */

Integer M; /* M 為每一個 stage 可結合的方式的數量 */

Matrix A; /* 可結合矩陣 A */

Array C; /* 記錄可結合方式的陣列,每一元素為兩個可相結合的 partial concurrent path 的索引產生的數對 */

ALGORITHM:

{

N = number of item in ArrayP;

allocate an integer matrix A with size (N+1)×(N+1);

/*

初始化第一個stage 的可結合矩陣,同時將所有可合併的組合 存在陣列 C 中,以變數 M 計算其個數。

*/

initialize M = 0;

for all partial concurrent path pair Pi, Pj in ArrayP, 0 ≤ I < j < N

{

if Pi can be combined with Pj { // 能合併則將數對(i,j)存入 C 中 add (i,j) into C with index M;

// 將索引存在可結合矩陣A 中 A[i][j] = A[j][i] = M;

increase M by 1;

} else {

// 若不能合併則在矩陣 A 中填入代表不合法的索引-1 A[i][j] = A[j][i] = -1;

} }

/*

若尚有可以合併的partial concurrent path,

則開始一個stage 的選取。

*/

while M > 0 {

// 尋找最大分數的組合方式,因為分數必≥0,故最大值初始化為-1 initialize maximum score as -1;

for all combination Ct in C {

// 提取出其partial concurrent path 索引的數對(i,j) extract Ct as (i,j);

// 依公式計算每一個組合的分數 score = M – 1;

for all partial concurrent path Pk in ArrayP, 0 ≤ k < N

{

if (A[i][k] ≥ 0) or (A[j][k] ≥ 0) { /* 若可結合矩陣存的值≥0 則表示可結合 */

// 依之前推論,此時分數應減 1 score = score – 1;

} }

// 檢查是否為目前最大分數

if score is bigger than maximum score { update maximum score to score;

Cmax = Ct; // 將擁有最大分數的組合記錄在變數 cmax中 }

}

// 組合 Cmax擁有最大分數,這個stage 決定使用這個組合 extract Cmax as (i,j);

lookup index i and j in ArrayP as Pi, Pj;

combine Pi and Pj into partial concurrent path P’;

// 將 P’暫存在 ArrayP的最後面, index = (N-1) add P’ into ArrayP with index N,

increase N by 1;

/*

根據之前的推論更新結合候選陣列C 並計算 P’的可結合情形 */

// 從C刪除 Pi與 Pj的組合,應一併更新矩陣 A,演算法後述 delete Cmax from C;

for all partial concurrent path Pk in ArrayP, 0 ≤ k < N, i ≠ k, j ≤ k

{

if (A[i][k] ≥ 0) and (A[j][k] ≥ 0) { // 將 Pk與 P’的組合加進組合候選中

add (k, N-1) into C with index M;

A[k][N-1] = A[N-1][k] = M;

increase M by 1;

}

else {

// 標記 Pk與 P’不能合併

A[k][N-1] = A[N-1][k] = -1;

}

if A[i][k] ≥ 0 {

delete index A[i][k] from C;

}

if A[j][k] ≥ 0 {

delete index A[j][k] from C;

}

}

/* 刪除 Pi與 Pj,應一併搬移可結合矩陣 A,演算法後述 */

delete Pi and Pj from ArrayP; } // stage 結束,開始下個 stage

/*

已無可以合併的組合,由partial concurrent path 產生 concurrent path

*/

for all partial concurrent path Pi in ArrayP

{ /*

每個partial concurrent path Pi是一個陣列,

儲存每個Run 的 path 的索引,或以 0 表示該 Run 沒有 path,

則應選擇該Run 中存取 shared object 最少次的 path,

以減少測試時的負擔。

*/

for all Run in system Runr

{

if Pi[r] = 0 {

Pi[r] = path index that access shared objects fewest times in Runr;

} } }

}

TARGET:

自組合候選陣列 C 中刪除一個組合,並更新相關的資料 INPUT:

Integer index; /* 欲刪除的組合在陣列 C 中的索引 */

Array C; /* 組合候選陣列 C */

Integer M; /* 組合候選數目 */

Matrix A; /* 可結合矩陣 */

OUTPUT:

Array C; /* 更新後的組合候選陣列 C */

Array C; /* 更新後的組合候選陣列 C */