• 沒有找到結果。

記憶體管理模組(Memory Management Module)

記憶體管理模組負責維護 UCT 結構、節點管理、並且提供兩個用於 分配節點空間的類別。

3.2.1 UCT 結構

在本軟體框架中,我們依據 2.2.3 提及的無鎖樹平行方式來實作。節 點只包含維持樹狀結構以及執行 MCTS 必要的欄位。若開發者需要擴充 每個節點紀錄的資訊,須繼承基底節點類別後,再加入需要的欄位。惟 須注意的是,節點大小會對實際記憶體用量有顯著影響,開發者須避免 增加不必要的欄位。

3.2.2 節點管理

在節點管理上,我們使用了分頁的概念,每次向系統索取一定數量的 節點,稱之為一個分頁(page),管理方式如圖 5。同時,我們用一個 32 位元的整數來表達節點的位置,並封裝成 NodePtr 類別;藉此降低在 64 位元系統中,維持樹狀結構所需消耗的記憶體。NodePtr 格式如圖 6,

利用前 n 個高位元,表達該節點是在第幾個分頁,並利用末 m 個低位元,

表達該節點在分頁中的位置。

圖 5. 分頁管理示意圖

圖 6. NodePtr 格式

在實際使用上,NodePtr 必須轉換成原生的指標,才能取得該節點 內的資料,轉換過程如表 4:

procedure resolve_address(node)

1. offset  right m bits of node.index 2. index  node.index >> m

3. page  GetPage(index)

4. return page.GetNode(offset)

表 4. NodePtr 轉換流程

首先從 NodePtr 中,利用位元運算子取得該節點在第幾個分頁,以及 為該分頁中第幾個節點;取得該分頁後,再從分頁中取得節點實際位置。

3.2.3 節點分配

在節點分配上,我們提供了兩個類別來協助節點分配。一個分頁分配 者(Page Allocator)以及每個執行緒有自己的節點分配者(Node Allocator)。

分頁分配者,負責向作業系統取得分頁,維護一個索引陣列以便能從 NodePtr轉換成原生指標,並提供分頁給各個執行緒的節點分配者,流 程如表 5。

procedure allocate_page()

1. if MAX_PAGE pages exceeded then 2. return null

3. end if

4. if not PA.has_free_page() then 5. allocate new page from system 6. end if

7. page  PA.consume_page() 8. return page

表 5. 向分頁分配者取得分頁流程

分 頁 分 配 者 在 提 供 分 頁 時 , 首 先 確 認 是 否 使 用 的 分 頁 已 超 過 MAX_PAGE,若使用數量已超過,回傳 null 並修剪搜尋樹,釋放無用的 空間;接著檢查當下是否有空的分頁可以使用,若沒有則向系統取得新 的分頁;最後將一個空的分頁回傳給節點分配者。

每個執行緒有一個獨立的節點分配者。負責向分頁分配者取得獨佔的 分頁,並從該分頁中提供節點空間給展開時使用,流程如表 6。

procedure allocate_nodes(n)

1. if not page.has_enough_nodes(n) then 2. allocate new page from Page Allocator

3. end if

4. first  page.consume_nodes(n) 5. return first

 bool prunePolicy(parent, keeplist);

傳入父節點(parent),若該節點需被設為未展開,則回傳 true;否 則回傳 false,並在 keeplist 內紀錄要保留的子節點。

軟體框架修剪搜尋樹的流程如下表 7;在下列示意圖中,深色區塊表 示原本的搜尋樹上,我們想要保留的部分。

1.

建立一個暫存用的索引陣列,並取得一個新的分頁,複製根節點至該分頁。

2.

遞迴的根據 PrunePolicy 從原本的搜尋樹複製節點至新的分頁上,在過 程中可能會需要更多的新分頁。

3.

用新分頁取代原本索引陣列的部分分頁。

4.

移除暫存的索引陣列,並清空剩餘的分頁。

表 7 修剪搜尋樹示意圖

相關文件