1. Trang chủ
  2. » Luận Văn - Báo Cáo

Luận văn thạc sĩ Khoa học máy tính: Tăng tốc giải thuật BWA-MEM trên nền tảng phần cứng

88 1 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Tăng tốc giải thuật BWA-MEM trên nền tảng phần cứng
Tác giả Lưu Hữu Quyết
Người hướng dẫn TS. Phạm Quốc Cường
Trường học Đại học Quốc gia Tp. Hồ Chí Minh
Chuyên ngành Khoa học máy tính
Thể loại Luận văn thạc sĩ
Năm xuất bản 2018
Thành phố Tp. Hồ Chí Minh
Định dạng
Số trang 88
Dung lượng 1,31 MB

Cấu trúc

  • DANH SÁCH CÁC TỪ VIẾT TẮT (12)
  • GIỚI THIỆU ĐỀ TÀI (16)
    • 1.1 Tổng quan vấn đề (16)
    • 1.2 Động lực nghiên cứu (17)
    • 1.3 Đóng góp của đề tài (17)
    • 1.4 Cấu trúc của luận văn (18)
  • KIẾN THỨC NỀN TẢNG (19)
    • 2.1 Kiến Thức Nền Tảng Được Sử Dụng Trong (19)
  • BWA-MEM (19)
    • 2.1.1 Burrows-Wheeler Transform (BWT) (19)
    • 2.1.2 Chuyển đổi về chuỗi gốc ban đầu: BWT-reversing (21)
    • 2.1.3 FM-Index (Full-text index in Minute space) (23)
    • 2.1.4 Smith-Waterman (SW) (27)
    • 2.2 GPU & CUDA (32)
      • 2.2.1 Graphics Processing Unit - GPU (32)
      • 2.2.2 Compute Unified Device Architecture - CUDA (33)
  • BURROWS-WHEELER ALIGNER (BWA-MEM) (36)
    • 3.1 Cấu Trúc Chương Trình BWA-MEM (37)
      • 3.1.1 SMEM Generation (38)
      • 3.1.2 Seed Extension (40)
      • 3.1.3 Output Generation (44)
    • 3.2 Quá trình thực thi chương trình BWA-MEM (44)
      • 3.2.1 Dữ liệu đầu vào của BWA-MEM (44)
      • 3.2.2 Dòng chảy chương trình của giải thuật BWA-MEM (46)
  • trên CPU (46)
  • CÁC CÔNG TRÌNH LIÊN QUAN (48)
    • 4.1 Tăng tốc với FPGA (48)
    • 4.2 Tăng Tốc với GPU (53)
    • 4.3 Tăng tốc với tính toán song song (Parallel Com- (56)
  • puting) (56)
    • 4.4 Thiết bị thử nghiệm (57)
    • 4.5 Kết quả (58)
  • THIẾT KẾ HỆ THỐNG (59)
    • 5.1 Hệ thống tổng quan (59)
    • 5.2 Cấu trúc dữ liệu nhiều lớp (61)
  • HIỆN THỰC HỆ THỐNG (64)
    • 6.1 Hiện thực Smith-Waterman kernel trên GPU (64)
  • KẾT QUẢ THỰC NGHIỆM (69)
    • 7.1 Môi trường thực nghiệm (69)
      • 7.1.1 NVIDIA GeForce 940M (69)
      • 7.1.2 Intel Core i3-5010U CPU @ 2.10GHz (70)
      • 7.1.3 Dữ liệu thực nghiệm (71)
    • 7.2 Cách thức thực nghiệm (71)
      • 7.2.1 Chọn dữ liệu đầu vào cho BWA-MEM với Smith-Waterman (71)
  • Kernel (71)
    • 7.2.2 Cách đánh giá kết quả thực nghiệm (72)
    • 7.3 So sánh thời gian thực thi BWA-MEM giữa (75)
  • CPU thuần và CPU kết hợp GPU (75)
    • 7.4 So sánh thời gian thực thi Smith-Waterman (76)
  • kernel giữa CPU và GPU (76)
    • 7.5 Đánh giá kết quả (76)
      • 7.5.1 Toàn bộ chương trình BWA-MEM (76)
      • 7.5.2 Smith-Waterman kernel (77)
  • KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN (79)
    • 8.1 Kết luận (79)
    • 8.2 Hướng phát triển (79)
  • Tài liệu tham khảo (81)
    • LÝ LỊCH TRÍCH NGANG (84)
    • Phụ lục A (85)
    • Mã nguồn CUDA một số phân khúc quan trọng (85)

Nội dung

Trong báo cáo này, bằng cách tìm hiểu về giảithuật BWA-MEM, ngôn ngữ CUDA Compute Unified Device Architecturevà kiến trúc của NVIDIA 940M, chúng tôi đề xuất phương án cải tiến hiệnthực g

DANH SÁCH CÁC TỪ VIẾT TẮT

CUDA Compute Unified Device Architecture

FPGA Field Programmable Gate Array

GPGPU General-Purpose Graphics Processing Units

BWA-MEM Burrows-Wheeler Aligner - Maximal Exact Match

FM-index Full-text Minute-space

LF-mapping Last-to-First column mapping

DRAM Dynamic Random-Access Memory

DRAM Dynamic Random Access Memory

BRAM Block Random Access Memory

FIFO First In First Out bp base-pair

2.1 Tổng quan xây dựng chuỗi BWT [11] 5

2.4 Minh họa BWT Reversing trực quan [11] 8

2.5 Thành phần chính của FM-index [11] 9

2.6 Các bước thực hiện truy vấn với FM-index [11] 10

2.7 Vị trí trùng lắp trong BWT [11] 10

2.8 Phương pháp tính điểm của thuật toán Smith-Waterman [15] 15

2.9 Khởi tạo ma trận tính điểm [15] 15

2.10 Tính toán giá trị cho mỗi ô [15] 16

2.12 Quá trình tìm kết quả [15] 17

2.13 Phân cấp bộ nhớ CUDA 19

2.14 Thành phần một chương trình của một ứng dụng GPU 20

3.1 Thứ tự thực thi 3 khối của giải thuật BWA-MEM [17] 22

3.2 Quá trình Seed Generation và Seed Extention [21] 26

3.3 Ví dụ quá trình Seed Generation và Seed Extention [5] 28

3.4 Ví dụ về một đoạn dữ liệu trong tập tin FASTQ 30

3.5 Dòng chảy của chương trình của giải thuật BWA-MEM 31

4.1 Mô hình hiện thực tăng tốc Seed Extension của bài báo [17] 35

4.2 Cấu hình của PE-Module: (a) standard systolic array configu- ration;(b) Variable Logical Length configuration that can by- pass part of the array; (c) Variable Physical Length config- uration that matches systolic array length to read length; (d)GPU-like single-PE modules [17] 35

4.3 Kiến trúc của tra cứu mảng hậu tố [26] 37

4.4 Kiến trúc của mô hình tăng tốc ma trận Smith-Waterman ở bài báo [27] 37

4.5 Mô hình hiện thực tăng tốc Seed Extension trên GPU của bài báo [28] 39

4.6 Mô hình hiện thực tăng tốc Seed Extension được cải tiến trên

4.7 Mô hình hiện thực tăng tốc BWA-MEM trong bài báo [29] 41

5.1 Mô hình hiện thực tăng tốc ma trận Smith-Waterman trên GPU 45

5.2 Ví dụ về một đoạn dữ liệu trong tập tin FASTQ 47

6.1 Ma trận Smith-Waterman đơn giản 50

6.2 Các bước tính toán song song ma trận Smith-Waterman 51

6.3 Minh họa đơn giản cách các Thread tính toán ma trận Smith-

7.1 Các Thread trong Warp cùng đọc biến a của mảng các cấu trúc dữ liệu 58

7.2 Các Thread trong Warp cùng đọc biến a 58

7.3 Các nhánh của if/else được thực hiện tuần tự 58

7.4 if/else áp dụng trên 2 Warp khác nhau 59

7.5 So sánh thời gian thực thi giữa BWA-MEM với Smith-Waterman

Kernel và BWA-MEM phiên bản gốc, CPU: 1 Thread 60

7.6 So sánh thời gian thực thi giữa Smith-Waterman Kernel trên

CPU và GPU, CPU: 1 Thread 61

7.7 Kết quả phân tích quá trình gọi các Runtime API của CUDA bằngnvprof 62

2.1 Thứ tự của các ký tự trongT bwt 6

2.4 Ví dụ ma trận thay thế 13

2.5 Ví dụ ma trận tính điểm 14

4.1 Kết quả phân tích chương trình BWA-MEM 34

4.2 Cấu hình phần cứng máy chủ (CPU-only) - : không có thông tin 43

4.3 Cấu hình phần cứng thiết bị - : không dùng 43

4.4 Kết quả đạt được *: Smith-Waterman Algorithm only 43

GIỚI THIỆU ĐỀ TÀI

Tổng quan vấn đề

Ngày nay, đứng trước nguy cơ đối mặt với những vấn đề sức khỏe nghiêm trọng, con người ngày càng đẩy mạnh nghiên cứu đối với các vấn đề liên quan đến sinh học và công nghệ gen nhằm tìm ra những giải pháp cho các vấn đề trên Trong những năm qua, với sự trợ giúp của những ngành khoa học khác, ngành sinh học và công nghệ gen đã gặt hái được nhiều thành tựu đáng kể, đặc biệt là sự chuyển dịch từ cấu trúc của các đa phân tử sinh học sang phân tích trình tự sinh học Theo dữ liệu về các trình tự sinh học có tại National Center for Biotechnology Information (NCBI) của Mỹ, đã có tới 120GB chứa khoảng 9 Gbase (Gbase hay còn gọi là Giga base pairs là một cặp bazơ gồm 2 nucleotid đối ngược nhau trong chuỗi xoắn kép) [1] Việc phân tích, tìm kiếm, so sánh, trong dữ liệu gen lớn như vậy đòi hỏi nhiều thời gian cũng như tính chính xác trong quá trình thực thi, do đó việc phát triển các giải thuật so sánh tuần tự trong lĩnh vực sinh học là khá quan trọng.

Qua đó ta thấy lĩnh vực máy tính cũng góp phần không nhỏ đối với lĩnh vực sinh học Bằng việc sử dụng các công cụ hỗ trợ từ tin học, công việc nghiên cứu trở nên dễ dàng và đảm bảo được sự chính xác cao, từ đó giúp cho công tác nghiên cứu về sinh học đặc biệt là công nghệ gen.

Động lực nghiên cứu

Sắp xếp trình tự gen mang đến nhiều lợi ích:

• Phát hiện được bệnh tế bào máu hình lưỡi liềm [2].

• Thiết kế các peptide kháng thể [3].

• Xác định quan hệ tiến hóa loài [4].

Trong đề tài này, chúng tôi chọn GPU (thay vì chọn nền tảng FPGA, Multi- core, ) để tăng tốc thuật toán xếp trình tự gen bởi GPU có nhiều core nên phù hợp để thử nghiệm Mặt khác, quá trình thiết lập môi trường thử nghiệm dễ dàng và ngôn ngữ được sử dụng để lập trình GPU (cụ thể là dùng CUDA) là C/C++ Tuy nhiên, việc sử dụng ngôn ngữ C/C++ lập trình cho GPU không hề đơn giản so với lập trình tuần tự đơn thuần Nói cách khác, việc tiếp cận và hiện thực song song hóa một chương trình là cả một thử thách mới đối với chúng tôi khi tiếp cận vấn đề này Hiện nay có nhiều giải thuật xếp trình tự gen như BWA-MEM [5], Bowtie2 [6], Cushaw2 [7], GEM [8], AGILE [9],STELLR [10], và mỗi giải thuật đều có những ưu điểm và nhược điểm riêng Tuy nhiên trong đề tài này, chúng tôi quyết định chọn giải thuật BWA-MEM, vì đó là một giải thuật so trùng và sắp hàng một cách chính xác, nhanh chóng trong trình tự sinh học với độ dài genome lớn, cân bằng tốt (scale well) đối với vộ genome lớn và đặc biệt là mã nguồn mở (điều này dễ dàng trong việc tìm hiểu và hiện thực giải thuật trên nền tảng GPU).

Đóng góp của đề tài

Đề tài có các đóng góp sau.

1 Phân tích cấu trúc chương trình BWA-MEM.

2 Tăng tốc chương trình BWA-MEM trên nền tảng GPU.

Cấu trúc của luận văn

Luận văn được chia thành 8 chương theo cấu trúc như sau:

1 Giới thiệu tổng quan các vấn đề trong Sinh-Tin học, động lực nghiên cứu, đóng góp của đề tài và trình bày cấu trúc luận văn.

2 Các kiến thức nền tảng được trình bày trong giải thuật BWA-MEM như:

Burrows-Wheeler Transform (BWT), Full-text index Minute-space (FM- index), giải thuật Smith-Waterman (SW) và kiến thức nền tảng GPU, CUDA.

3 Phân tích cấu trúc chương trình BWA-MEM.

4 Tìm hiểu các công trình liên quan đến đề tài, quan sát và nhận định.

5 Trình bày ý tưởng và cách thức hiện thực chương trình trên GPU, 6 Trình bày kết quả thực nghiệm, đánh giá và phân tích kết quả.

7 Trình bày về kết luận vấn đề các giới hạn và công việc tiếp theo của đề tài trong tương lai.

KIẾN THỨC NỀN TẢNG

BWA-MEM

Burrows-Wheeler Transform (BWT)

Giải thuật được sử dụng trong kỹ thuật nén dữ liệu theo ý tưởng sắp xếp lại các ký tự trong một chuỗi để tạo ra một chuỗi có nhiều các ký tự giống nhau dồn lại với nhau hơn chuỗi ban đầu và có thể chuyển đổi từ chuỗi này lại chuỗi ban đầu Thuật toán tạo ra chuỗi BWT có thể mô tả như sau với chuỗi abaaba Ta kí hiệu chuỗi abaaba làT.

Bước 1: Viết thêm vào cuối T một kí tự là $ (đại diện cho con trỏ EOF), xét n+1 hoán vị vòng quanh, ta được: abaaba$ baaba$a aaba$ab aba$aba ba$abaa a$abaab

Bước 2: Sắp xếp n+1 hoán vị vòng quanh đó theo thứ tự từ điển tạo thành ma trận BWT.

$abaaba a$abaab aaba$ab aba$aba abaaba$ ba$abaa baaba$a

Bước 3: Viết ra các ký tự cuối của các hoán vị vòng quanh theo đúng thứ tự sau khi đã sắp xếp tạo thành từ mã BWT của T: abba$aa Dưới đây Hình 2.1 sẽ mô tả tổng quan quá trình xây dựng chuỗi BWT.

Hình 2.1: Tổng quan xây dựng chuỗi BWT [11]

Chuyển đổi về chuỗi gốc ban đầu: BWT-reversing

Xét ma trận BWT (MT) cột đầu và cột cuối ký hiệu là F và L, đánh thứ tự cho các ký tự ở 2 cột này T bwt là chuỗi BWT được tạo ra từ M T

M T có tính chất "Last-to-First column mapping" (LF-mapping) nghĩa là sự xuất hiện thứ i của ký tự ở cột cuối cùng (L) tương ứng với sự xuất hiện thứ i của ký tự đó ở cột đầu tiên (F) Theo [12], LF-mapping có:

• C(ã) biểu thị mảng chiều dài |Σ| sao cho C[c] chứa tổng số lần xuất hiện của các ký tự trong dữ liệu text có thứ tự từ điển nhỏ hơn ký tự c.

• Occ(c,q) biểu thị số lần xuất hiện của ký tự c trong tiền tố (prefix) T bwt [1,q].

LF(ã) đại diện cho Last-to-First column mapping bởi vỡ ký tự T bwt [i] ở cột cuối L của ma trận M T sẽ nằm ở cột đầu F tại vị trớ LF(i) và LF(ã) cũng cho phép dò ngược chuỗi T Cụ thể, nếu T[k] = T bwt [i] thì T[k-1] = T bwt [LF(i)].

Ví dụ T = "abaaba" Dựa vào Hình 2.1 ta cóT bwt = "abba$aa".

Bảng 2.1: Thứ tự của các ký tự trongT bwt

• Xây dựng Occ(c,q) của T bwt

LF(5) = C($) + Occ($,5) = 0 + 1 = 1 => L(5) = F(1) = $ Ta được chuỗi T = a3b1a1a2b0a0 (Hình 2.4).

Hình 2.2: LF-mapping [11] Để chuyển về chuỗi gốc ban đầu, ta đảo ngược chuỗi bắt đầu từ phía phải của chuỗi gốc dò ngược về phía trái Cách thực hiện đảo ngược được trình bày như Hình 2.3 và Hình 2.4 Kết quả thu được như sau:a 3 b 1 a 1 a 2 b 0 a 0 $ = T.

Hình 2.4: Minh họa BWT Reversing trực quan [11]

FM-Index (Full-text index in Minute space)

FM-index [13] cho phép tìm kiếm chuỗi con trùng một cách hiệu quả bên trong dữ liệu text.

FM-index kết hợp kỹ thuật BWT với một vài cấu trúc dữ liệu phụ trợ để nhằm giảm bộ nhớ thực thi và thực hiện nhanh hơn.

Thành phần chính của FM-index bao gồm F (có thể được trình bày rất đơn giản 1 số nguyên cho 1 ký tự) và L (có thể nén được) từ ma trận BWT (Hình 2.5) FM-index có khả năng tiết kiệm không gian cần để lưu trữ.

Hình 2.5: Thành phần chính của FM-index [11]

Truy vấn với FM-Index: việc truy vấn bằng cách sử dụng LF-mapping được mô tả như sau.

• Ví dụ cần truy vấn chuỗi P = aba Ta truy vấn như Hình 2.6.

• Đã tìm được chuỗi P là có trong T và truy vấn này có cùng kết quả với mảng hậu tố (Hình 2.7).

Thuật toán cho FM-index [12]: xét chuỗi con trùng P[1,p] trong dữ liệu text T[1,n] Giá trị occ là số lượng của những lần xuất hiện của chuỗi con trùng P[1,n] trong dữ liệu text nén T bwt Hai thủ tục chính để vận hành FM- index:

1 Xác định số lượng của những lần xuất hiện của chuỗi con trùng P[1,p] trong dữ liệu nénT bwt sử dụng thuật toán get_row (Algorithm 1) Tham số First trỏ đến hàng đầu tiên của ma trận BWT (MT) chứa tiền tố P[i, p] và tham số Last trỏ đến hàng cuối của MT chứa tiền tố P[i, p].

Thuật toán trả về giá trị occ = Last - First + 1.

2 Xác định những vị trí của của chuỗi con trùng P[1,n] ở trong dữ liệu text T sử dụng thuật toán get_position (Algorithm 2) trả về occ giá trị nguyên khác nhau trong khoảng [1,n].

Hình 2.6: Các bước thực hiện truy vấn với FM-index [11]

Hình 2.7: Vị trí trùng lắp trong BWT [11]

Algorithm 1Thuật toán get_rows để tìm những hàng chứa tiền tố P[1,n] [12]

Function GET _ ROWS (P [1, p]) begin i ← p, c ← P ]p F irst ← C[c] + 1, Last ← C[c + 1]; while ((F irst ≤ Last) and (i ≥ 2)) do c ← P [i − 1];

Last ← C[c] + Occ(c, Last); i ← i − 1; end if Last < F irst then return no rows pref ixed by P [1, p]; end else return (First,Last); end end

Algorithm 2Thuật toán get_position cho việc tính toán Pos(i) [12]

Function GET _ POSITION (i) begin i 0 ← i, t ← 0 ; while row i’ is not marked do i 0 ← LF [i 0 ]; t ← t + 1; end return Pos(i’) + t; end

Ví dụ: Truy vấn chuỗi P = aba trong dữ liệu text T = aabaaba.

1 TìmT bwt Dựa vào Hình 2.1 ta có T bwt = abba$aa.

2 Áp dụng tiến trình của FM-index.

Bước 1: Sử dụng thuật toán get_rows (Algorithm 1).

• Ký tự đầu tiên chúng ta cần truy vấn là a, ký tự cuối cùng trong chuỗi P Khoảng [First,Last] ban đầu được thiết lập là:

• Ký tự kế tiếp cần truy vấn là b Khoảng [First,Last] mới là:

[C[b] + Occ(b, First-1) + 1, C[b] + Occ(b, Last)] = [5 + 0 + 1, 5 + 2] = [6,7] với First bằng 2 là chỉ số bắt đầu và Last bằng 5 là chỉ số kết thúc của khoảng [First,Last] trước đó [2,5].

• Ký tự cuối cùng cần truy vấn là a Khoảng [First,Last] mới là:

[C[a] + Occ(a, First-1) + 1, C[a] + Occ(a, Last)] = [1 + 2 + 1, 1 +4] = [4,5] P = aba có trong các hàng [4,5] của ma trận BWT.

• Giá trị occ = Last - First + 1 = 8 - 7 + 1 = 2.

Bước 2: Sử dụng thuật toán get_position ((Algorithm 2).

• i = Last = 5 Hàng r 5 của M T được đánh dấu, lấy Pos(5) từ T:

• i = First = 4. r 4 không được đánh dấu LF[4] = C(a) + Occ(a,4) = 1 + 2 = 3, t = 1; r 3 không được đánh dấu LF[3] = C(b) + Occ(b,3) = 5 + 2 = 7, t = 2; r 7 không được đánh dấu LF(7) = C(a) + Occ(a,7) = 1 + 4 = 5, t = 3; r 5 được đánh dấu Lấy Pos(5) từ T: Pos(5) = 1.

Vậy chuỗi aba sẽ nằm ở vị trí thứ 1 và vị trí thứ 4 trong T.

Smith-Waterman (SW)

Giải thuật Smith-Waterman xây dựng trên ý tưởng so sánh tìm ra những đoạn hay những miền của hai chuỗi trình tự có độ tương đồng cao nhất, từ đó đánh giá mức độ tương đồng giữa chúng.

Thuật toán Smith-Waterman [14] gồm 3 bước:

1 Khởi tạo ma trận từ hai chuỗi đầu vào A=a1a 2 an và B=b1b 2 bm với n và m lần lượt là độ dài chuỗi A và B.

• Xác định ma trận thay thế (substitution matrix).

– Mỗi ô trong ma trận thay thế sẽ nhận được một điểm số (score).

– Ví dụ: Nếu hai ký tự giống nhau sẽ nhận được điểm số +1, hai ký tự không giống nhau sẽ nhận điểm số -1, ma trận thay thế sẽ là:

– Ma trận thay thế sẽ được biểu diễn như sau: s(aj,bj) 

Bảng 2.4: Ví dụ ma trận thay thế

• Điểm phạt cho quãng cách (gap penalty).

– Quãng cách (gap được ký hiệu bằng dấu "-") được hiểu đơn giản khi nhìn trong trình tự là phần trống, không có ký tự để so sánh với ký tự của chuỗi khác Chẳng hạn, với chuỗi sau ’AAG-AT-A’ có hai quãng cách, mỗi quãng có một chỗ trống Còn với chuỗi ’AA–GATA’ có một quãng cách với hai khoảng trống.

– Điểm phạt cho quãng cách là điểm số cho việc thêm hoặc xóa quãng cách.

– Trong sinh học, điểm phạt cần phải được tính toán khác nhau bởi vì các sinh vật nào gần nhau sẽ có trình tự giống nhau ở các đoạn liên tục và dài vì vậy cũng sẽ có ít quãng cách hơn hoặc trường hợp đột biến gen có thể dẫn đến việc chèn nhiều quãng cách hơn Do đó, ta sẽ còn có thêm điểm phạt cho mỗi một đoạn quãng cách (open gap penalties) gồm điểm cho gap opening và điểm cho gap extension.

Ví dụ: A _ _ G C C Quãng cách gồm khoảng trống đầu tiên là gap opening và khoảng trống phía sau gọi là gap extension.

– W k = u * (k-1) + v (u>0, v>0) với W k điểm phạt cho quãng cách (gap penalty) có độ dài k v là điểm phạt cho gap open- ing u là điểm phạt cho gap extension [15].

• Xây dựng ma trận tính điểm (scoring matrix) H Kích thước của ma trận tính điểm là (n+1)*(m+1).

– Chức năng của ma trận tính điểm là để thực hiện so sánh trình tự lần lượt giữa tất cả các ký tự trong hai chuỗi để ghi lại kết quả so trùng và sắp hàng tối ưu.

Bảng 2.5: Ví dụ ma trận tính điểm. b 1 b j b m

2 Tính toán, điền giá trị cho ma trận (điểm cho mỗi ô). Điểm cho từng cặp ký tự phụ thuộc vào: điểm của hai ký tự giống nhau hoặc hai ký tự khác nhau (dựa vào ma trận thay thế) và điểm phạt quãng cách (gap penalty) Theo [15] ta có:

 H i−1,j−1 + s(ai, b j ) , max k≥1 {Hi−k,j - W k } , 1 ≤i ≤n,1 ≤ j ≤ m max l≥1 {Hi,j−l - W l } ,

H i−1,j−1 + s(ai, b j ) là điểm cho việc so trùng và sắp hàng a i , b j H i−k,j -W k là điểm số nếua i là vị trí kết thúc của quãng cách có độ dài k.

H i,j −l - W l là điểm số nếu b j là vị trí kết thúc của quãng cách có độ dài l.

0 nghĩa là không có sự giống nhau giữaa i và b j 3 Tìm ô có giá trị lớn nhất trong ma trận Sử dụng kỹ thuật lưu vết để tìm ra kết quả.

Hình 2.8: Phương pháp tính điểm của thuật toán Smith-Waterman [15]

Ví dụ [15]: so trùng và sắp hàng hai chuỗi TGTTACGG và GGTTGACTA.

1 Sử dụng ma trận thay thế (substitution matrix) s(ai,bj) 

−3 a i 6=b j và điểm phạt cho quãng cách (gap penalty) Wk = 2k với độ dài k là 1.

Ta sẽ xây dựng ma trận tính điểm (scoring matrix) (Hình 2.9).

Hình 2.9: Khởi tạo ma trận tính điểm [15]

2 Tính toán và điền giá trị cho ma trận dựa vào Hình 2.8 ta được Hình 2.10 và Hình 2.11.

Hình 2.10: Tính toán giá trị cho mỗi ô [15]

Hình 2.11: Ma trận tính điểm [15]

3 Sử dụng kỹ thuật lưu vết để tìm kết quả.

Hình 2.12: Quá trình tìm kết quả [15]

GPU & CUDA

Một bộ vi xử lý chuyên dụng, đảm nhận nhiệm vụ tăng tốc, xử lý đồ họa cho CPU Các GPU hiện nay có khả năng xử lý cao trong xử lý đồ họa máy tính.

Về tốc độ xử lý dữ liệu thì GPU có thể tiếp nhận hàng ngàn luồng dữ liệu cùng một lúc vì thế có thể tăng tốc một số phần mềm tới hơn 100 lần so với một CPU.

Trước khi GPU ra đời thì CPU vừa phải xử lý các chương trình vi tính, dữ liệu vừa kiêm luôn công việc xử lý đồ họa, hình ảnh Lượng công việc quá nhiều nên CPU hoạt động theo xu hướng ban phát đồng đều mức tài nguyên.

Công việc đồ họa và công việc văn phòng đều nhận được lượng tài nguyên như nhau Chính vì vậy các sản phẩm đồ họa khi ra đời đều bị hạn chế rất nhiều Nhưng từ khi GPU ra đời thì mọi thứ đã hoàn toàn thay đổi giúp giảm bớt khối lượng công việc cho CPU, CPU chỉ còn nhiệm vụ kéo hệ thống chạy theo hoạt động của GPU và dành các xung của mình cho các nhiệm vụ khác của hệ thống, tiết kiệm thời gian đáng kể và hiện nay vai trò của GPU trên máy tính ngày càng quan trọng hơn, không chỉ dừng lại ở việc xuất tín hiệu ra màn hình hay hỗ trợ chơi game 3D mà việc tận dụng nhân đồ hoạ (GPU) tham gia hỗ trợ xử lý cùng nhân CPU để đưa ra các ứng dụng bổ ích như:

DXVA (DirectX Video Acceleration) trên các chương trình xem phim, HWA (Hardware Acceleration) trên các trình duyệt web, MS Powerpoint 2010 tận dụng GPU để thể hiện các hiệu ứng mượt mà hơn [16].

2.2.2 Compute Unified Device Architecture - CUDA:

Một nền tảng có khả năng tính toán song song và lập trình được phát triển bởi NVIDIA vào tháng 11 năm 2006 nhằm mục đích tăng cường mạnh mẽ các khối tính toán song song trong các GPU và giúp cho các nhà phát triển thuận lợi hơn trong việc triển khai các ứng dụng non-graphic, CUDA hỗ trợ một số ngôn ngữ lập trình như C và Fortran, và nó có một thư viện lớn CUDA cung cấp môi trường tính toán phức hợp và có thể làm việc theo môi trường tính toán song song Một chương trình CUDA gồm có hai thành phần chính:

CPU và GPU Kernel Host code chạy trên CPU trong khi GPU kernel codes là những hàm GPU chạy trên những thiết bị GPU và được miêu tả trong Hình 2.14 Chương trình thực thi trên GPU hoàn toàn độc lập với chương trình trên CPU.

Một ứng dụng bắt đầu thực thi bằng code trên CPU Code trên CPU chỉ thị tới một kernel GPU trên thiết bị GPU Kernel này được thực thi trên một GPU grid.

Một GPU grid chứa các thread blocks hoàn toàn độc lập với nhau Một block chứa nhiều thread Có những giới hạn về số lượng threads/block và số thread blocks/grid Bởi vì vấn đề giới hạn bộ nhớ được chia sẻ cục bộ và kích thước dữ liệu hoặc số lượng processors hoặc kiến trúc của GPU.

Shared Registers Registers Thread(0,0) Thread(N,0)

Hình 2.13: Phân cấp bộ nhớ CUDA

Bộ nhớ CUDA có nhiều thành phần bộ nhớ phân cấp khác nhau được truy cập trong quá trình hoạt động, khác về kích thước và băng thông (Chi tiết được mô tả trong Hình 2.13) Bên trong mỗi thread đều có bộ nhớ cục bộ riêng (Local) và bộ nhớ chia sẻ (Shared memory) Bộ nhớ chia sẻ này sẽ được nhìn thấy trong tất cả mọi threads của block với thời gian sống là như nhau và bộ nhớ toàn cục (Global memory) được kết nối tới tất cả các threads Ngoài ra, Bộ nhớ CUDA còn có hai bộ nhớ chỉ đọc (read-only) đó là Constant memory và Texture memory Hai bộ nhớ này được liên kết đến tất cả các threads Việc thêm hai bộ nhớ này nhằm tối ưu chi phí tính toán.

Input và Output dữ liệu được dịch chuyển từ CPU tới GPU và ngược lại Để khai thác GPU một cách hiệu quả thì bản thân CPU Host phải xây dựng cấu trúc dữ liệu phù hợp với GPU.

Vấn đề quan trọng cuối cùng về CUDA đó là vấn đề đồng bộ bộ nhớ CUDA giúp điều phối các threads trong block sử dụng bộ nhớ chia sẻ một cách công bằng Khi gọi một kernel thực tế là gọi một grid Những Host codes trong

Hình 2.14: Thành phần một chương trình của một ứng dụng GPU một ứng dụng CUDA trải qua bảy bước sau.

1 Khởi tạo một thiết bị 2 Cấp phát bộ nhớ GPU 3 Dịch chuyển dữ liệu tới thiết bị 4 Chỉ định những kernels

5 Dịch chuyển dữ liệu từ thiết bị6 Giải phóng bộ nhớ trên GPU7 Reset thiết bị

BURROWS-WHEELER ALIGNER (BWA-MEM)

Cấu Trúc Chương Trình BWA-MEM

Giải thuật BWA-MEM bao gồm ba khối chính được thực thi tuần tự cho mỗi chuỗi đọc được từ tập dữ liệu:

1 SMEM Generation 2 Seed Extension 3 Output Generation

Giải thuật BWA-MEM xử lý các chuỗi đọc từ tập dữ liệu theo kiến trúc bó [17], như Hình 4.4 Đầu tiên, hai giai đoạn SMEM Generation và Seed Extension được thực thi tuần tự liên tục cho mỗi chuỗi đọc được từ tập dữ liệu, khi hai quá trình này hoàn thành cho một bó dữ liệu, giai đoạn ghi kết quả được thực thi Quá trình xử lý cho các bó dữ liệu khác sẽ được tiếp tục.

Giải thuật BWA-MEM xử lý theo bó này thường được hiện thực theo mô hình xử lý đa nhiệm (multithreads).

Hình 3.1: Thứ tự thực thi 3 khối của giải thuật BWA-MEM [17]

Chuỗi MEM là chuỗi con của chuỗi đọc được từ tập dữ liệu mà trùng lắp chính xác với chuỗi DNA tham khảo và không thể mở rộng theo bất kỳ chiều nào.

Chuỗi SMEM [18] là một chuỗi MEM mà không thể được chứa trong một chuỗi lớn hơn nào khác có đặc tính tương tự.

Chuỗi SMEM thường được tìm thấy ít hơn nhiều so với chuỗi MEM.

Mỗi một chuỗi đọc được từ tập dữ liệu có thể không có chuỗi SMEM nào hoặc nhiều chuỗi SMEM.

Các SMEM này chính là seed Các SMEM này có thể dễ dàng tạo được bằng cách sử dụng FM-Index [19].

Hit là số chuỗi MEM hoặc SMEM có trong trong bộ gen tham khảo.

Chuỗi đọc từ tập dữ liệu R =CTGACAGATCAGAGAGGAATCCGA và bộ gen tham khảo T= CTGCGTCAACAGATCAGAGAGCTCCGATCTCCGA CCGCTGACATATCAGAGAGGAATCGGACGTA

• Ta tìm được 4 MEM là R[1 6], R[4 16], R[8 21] và R[20 24].

Ba chuỗi MEM R[1 6], R[4 16], R[8 21] có 1 hit trong gen tham khảo T.

Chuỗi MEM R[20 24] có 2 hit trong gen tham khảo T.

Theo [5] BWA-MEM xác định các seed bằng hai bước:

• Xác định tất cả các chuỗi SMEM có trong chuỗi gen tham khảo dựa vào thuật toán tìm SMEMs [18] (Algorithm 5) Thuật toán tìm SMEMs sẽ sử dụng hai thuật toán Backward Extension (Al- gorithm 3) và giải thuật Forward Extension (Algorithm 4)

Algorithm 3Thuật toán Backward Extension [18]

Input: Bi-interval [k, l, s] of string W and a symbol a

Output: Bi-interval of string aW

Function B ACKWARD E XT ([k, l, s], a) begin for b ← 0 to 5 do k b ← C(b) + O(b, k − 1) s b ← O(b, k + s − 1) − O(b, k − 1) end l 0 ← l l 4 ← l 0 + s 0 for b ← 3 to 1 do l b ← l b+1 + s b+1 end l 5 ← l 1 + s 1 return [k a , l a , s a ] end

Algorithm 4Thuật toán Forward Extension [18]

Input: Bi-interval [k, l, s] of string W and a symbol a

Output: Bi-interval of string W a

Algorithm 5Thuật toán tìm SMEMs [18]

Input: String P and start position i 0 ; P [−1] = 0

Output: Set of bi-intervals of SMEMs overlapping i 0

Initialize Curr, Prev and Match as empty arrays [k, l, s] ← [C(P[i 0 ]), C (P[i 0 ]), C (P [i 0 ] + 1) − C(P [i 0 ])] for i ← i 0 + 1 to |P | do if i = |P | then

Append [k, l, s] to Curr end else

Append [k, l, s] to Curr end if s 0 = 0 then break end

Swap array Curr and Prev i 0 ← |P | for i ← i 0 − 1 to −1 do

Reset Curr to empty s 00 ← −1 for [k, l, s] in Prev do

[k 0 , l 0 , s 0 ] ←B ACKWARD E XT ([k, l, s], P [i]) if s 0 = 0 or i = −1 then if Curr is empty and i + 1 < i 0 + 1 then i 0 ← i Append [k, l, s] to Match end end if s 0 6= 0 and s 0 6= s 00 then s 00 ← s 0 Append [k, l, s] to Curr end end if Curr is empty then break end

Swap Curr and Prev end return Match end

Chuỗi gen được đọc từ tập dữ liệu: R = CCCCGTTTT và chuỗi gen tham khảo: T = CCCCATTTT CCCCG .GTTTT .

– Chuỗi con CCCCATTTT của T là 1-mismatch hit (hit có 1 ký tự không trùng) của R mà đó là true hit Chú ý rằng các MEM của R là CCCCG và GTTTT Bởi vì 1-mismatch hit (hit có 1 ký tự không trùng) của CCCCATTTT không chứa hai MEM của R, vì thế bước seeding bị thất bại trong việc tìm 1-mismatch hit này.

• Để tránh xác định thiếu seed, re-seeding được tiến hành để tìm kiếm những seed có độ dài quá lớn (trên 28 bp) Giả sử một SMEM có độ dài l xuất hiện k lần trong bộ gen tham khảo Bước re-seeding sẽ tìm những chuỗi trùng lắp chính xác dài nhất (LEMs – longest exact matches) bao gồm phần giữa của SMEM và xuất hiện ít nhất k + 1 lần trong bộ gen tham khảo Ý tưởng này đảm bảo các seed được xác định từ bước seeding và bước re-seeding có thể bao gồm phần lớn tất cả những true hit của chuỗi đọc từ tập dữ liệu.

Xét tất cả những seed thu được từ seeding và re-seeding, chúng ta có thể thực hiện seed extension cho tất cả chúng Tuy nhiên, ở đây có thể có nhiều seed và phần lớn trong số đó là dư thừa Để giảm seed extension dư thừa ở bước sau, bước chaining được thực hiện để gộp những nhóm seed thẳng hàng và nằm gần nhau (được gọi là chain) và sau đó lọc bỏ những chain ngắn mà phần lớn độ dài của chúng được chứa trong chain dài Chain được phát hiện trong bước này không cần chính xác.

Các seed là các chuỗi con của chuỗi đọc từ tập dữ liệu mà trùng lắp chính xác với gen tham khảo đã tìm được ở bước SMEM Generation Sau khi tìm được seed, seed sẽ được mở rộng theo cả hai chiều để thực hiện việc so trùng và sắp hàng chuỗi đọc từ tập dữ liệu với gen tham khảo Hình 3.2 là ví dụ của hai quá trình Seed Generation và Seed Extention.

Hình 3.2: Quá trình Seed Generation và Seed Extention [21]

Quá trình mở rộng này thường dùng phương pháp quy hoạch động (dy- namic programming) dựa trên giải thuật Smith-Waterman [14].

Quy hoạch động (dynamic programing) là một phương pháp giảm thời gian chạy của các thuật toán thể hiện các tính chất của các bài toán con gối nhau (overlapping subproblem) và cấu trúc con tối ưu (optimal substructure). Áp dụng vào giải thuật Smith-Waterman thì bài toán con ở đây chính là tính toán một điểm cho một phần tử của ma trận, các phần tử của ma trận này có cách tính điểm như nhau (cấu trúc con) và output của phần tử này là input của phần tử khác (gối đầu) Và điều này dẫn đến việc rất thích hợp để ứng dụng FPGA (FPGA-Based Systolic Array) vào kernel Seed-Extension để tăng tốc cho BWA-MEM.

Xác định và lựa chọn vùng ánh xạ:

• Việc so trùng và sắp hàng cục bộ với điểm phạt quãng cách, số điểm dương cho hai ký tự giống nhau thường nhỏ hơn điểm phạt cho hai ký tự khác nhau hoặc cho một gap.

• Độ dài của việc so trùng và sắp hàng cục bộ tối ưu của chuỗi đọc từ tập dữ liệu S tới bộ gen tham khảo T không thể lớn hơn 2 lần độ dài của chuỗi đọc từ tập dữ liệu (|S|) bởi vì việc so trùng và sắp hàng cục bộ yêu cầu một số điểm dương.

• P mem là vị trí bắt đầu của MEM trong tập dữ liệu, T mem là vị trí ánh xạ của MEM ở trong bộ gen tham khảo và L mem là độ dài của MEM.

Vùng ánh xạ nằm trong khoảng [Ta,T b ]:

T a = T mem - 2(Pmem + 1) T b =T mem +L mem + 2(|S| -P mem -L mem )

• Tính toán điểm số sắp hàng cục bộ tối ưu cho tất cả những vùng ánh xạ đã xác định của tập dữ liệu S sử dụng thuật toán SW, sau đó xây dựng danh sách của tất cả những vùng ánh xạ theo thứ tự điểm giảm.

• Vùng ánh xạ nào có số điểm nhỏ hơn ngưỡng điểm tối thiểu thì sẽ bị loại bỏ khỏi danh sách. Ở bước mở rộng này, mỗi seed thu được sẽ được xếp hạng bởi độ dài của chain chứa nó và sau đó đến độ dài của seed đó Các seed sẽ mở rộng lần lượt theo danh sách xếp hạng seed từ tốt nhất đến xấu nhất và loại bỏ những seed nếu nó đã nằm trong chuỗi so trùng và sắp hàng được tìm thấy trước đó. Để tiết kiệm thời gian, BWA mở rộng hạt seed sử dụng quy hoạch động điểm phạt quãng cách (banded affine-gap-penalty dynamic programming) [5].

Theo [5] bước mở rộng hạt (seed extension) của BWA-MEM khác với bước mở rộng hạt tiêu chuẩn ở hai khía cạnh:

• Giả sử ở bước mở rộng chúng ta đi đến vị trí tham khảo x với số điểm mở rộng tốt nhất đạt được ở vị trí truy vấn y BWA-MEM sẽ ngừng mở rộng nếu có sự khác biệt giữa điểm mở rộng tốt nhất và điểm số tại (x,y) là lớn hơn Z+|x-y|*pgapExt, trong đóp gapExt là điểm phạt mở rộng quãng cách (gap extension penalty) và Z là điểm cắt.

Quá trình thực thi chương trình BWA-MEM

Mã nguồn phần mềm mở giải thuật BWA-MEM được tham khảo từ [23] Đây là đường dẫn đến một GitHub Repository được sử dụng để bảo trì và phát triển gói phần mềm Burrow-Wheeler Aligner (BWA) bao gồm nhiều công cụ so trùng và sắp hàng chuỗi gen bằng nhiều giải thuật khác nhau được phát triển bởi tiến sĩ Heng Li, các đồng nghiệp của ông và cộng đồng mã nguồn mở GitHub BWA-MEM là một trong những giải thuật này, phiên bản của phần mềm BWA-MEM mà chúng tôi sử dụng để tham khảo là 0.7.16a-r1181.

3.2.1 Dữ liệu đầu vào của BWA-MEM

Dữ liệu đầu vào của BWA-MEM bao gồm các tham số đầu vào ảnh hưởng trực tiếp đến kết quả xử lý dữ liệu của giải thuật, tập tin chứa dữ liệu gen tham khảo và tập tin đọc chứa chuỗi gen phân kỳ thấp Ý nghĩa của các tham số đầu vào của giải thuật BWA-MEM có thể được đọc kỹ lưỡng hơn qua đường dẫn sau đây [24] Ở trong đề tài này, nhằm phục vụ cho việc hiểu dòng chảy chương trình của giải thuật BWA-MEM, chúng tôi tập trung nhiều hơn đến định dạng của tập tin tham khảo và tập tin đọc chứa các chuỗi gen phân kỳ thấp.

Trong tin sinh học, tập tin chứa dữ liệu gen tham khảo mang định dạng FASTA Định dạng FASTA là kiểu định dạng văn bản đơn giản được sử dụng để biểu thị chuỗi nucleotide hoặc chuỗi peptide Trong đó, các nucleotides hoặc amino acids được biểu diễn bằng các ký tự chữ viết Một tập tin FASTA thường bao gồm hai phần chính Thứ nhất là dòng có dấu ">" ở đầu, mang thông tin miêu tả, định danh của chuỗi gen tham khảo mà nó đại diện Phần thứ hai là phần gen tham khảo Đây là ví dụ về nội dung của một đoạn văn bản định dạng FASTA ngắn.

MTEITAAMVKELRESTGAGMMDCKNALSETNGDFDKAVQLLREKGLGKAAKK ADRLAAEGLVSVKVSDDFTIAAMRPSYLSYEDLDMTFVENEYKALVAELEKE NEERRRLKDPNKPEHKIPQFASRKQLSDAILKEAEEKIKEELKAQGKPEKIW DNIIPGKMNSFIADNSQLDSKLTLMGQFYVMDDKKTVEQVIAEKEKEFGGKI KIVEFICFEVGEGLEKKTEDFAAEVAAQL

Khác với tập tin chứa dữ liệu gen tham khảo, tập tin đọc chứa các chuỗi gen phân kỳ thấp có định dạng FASTQ Trong Hình 3.4, từ trên xuống dưới, cứ bốn dòng là thông tin và nội dung của một chuỗi gen này.

Hình 3.4: Ví dụ về một đoạn dữ liệu trong tập tin FASTQ

1 Dòng thứ nhất bắt đầu với ký tự @ và sau đó là thông tin miêu tả cùng định danh của chuỗi ký tự.

2 Dòng thứ hai là nội dung chưa qua xử lý của chuỗi gen.

3 Dòng thứ ba bắt đầu với ký tự + và nối theo đó có thể là thông tin tương tự dòng thứ nhất.

4 Dòng thứ tư là chuỗi mã hóa giá trị chất lượng của dòng thứ hai.

Dòng thứ hai của thông tin mỗi chuỗi gen sẽ là dòng duy nhất được quan tâm trong các khâu so trùng và sắp hàng chuỗi gen của giải thuật BWA-MEM.

3.2.2 Dòng chảy chương trình của giải thuật BWA-MEM

trên CPU

Hình 3.5: Dòng chảy của chương trình của giải thuật BWA-MEM

Hình 3.5 mô tả đơn giản dòng chảy chương trình của BWA-MEM Trong đó:

Tác vụ đọc dữ liệu đầu vào làm các công việc cụ thể đó là:

• Tải FM-index đã được tạo thành sau bước /bwa index reference.fa.

• Tải các tham số cho giải thuật BWA-MEM được người dùng thiết lập,dữ liệu từ các tập tin fa và fq lên bộ nhớ chương trình.

Việc có sử dụng pipeline hay không cũng là một lựa chọn của người dùng phần mềm Trong trường hợp này, chúng ta hãy giả sử pipeline được sử dụng.

Từ thread chính đầu tiên của chương trình, hai thread phụ sẽ được thiết lập để đảm bảo khi hai thread này đi vào pipeline thì không có trường hợp hai thread thực thi một lúc cùng một bước Bằng cách sử dụng pipeline, chương trình tiết kiệm được thời gian đọc chuỗi từ tập tin đọc fq và thời gian ghi ra tập tin output sam.

Chương trình được tác giả lập trình theo cấu trúc pipeline gồm ba bước Hình 3.5:

• Bước một của pipeline, chương trình đọc n chuỗi từ tập tin đọc fq Nên nhớ rằng, đúng hơn là chương trình đọc n chuỗi từ dữ liệu của file fq đã được đọc lên bộ nhớ chương trình Tham số n là tham số được lựa chọn trước bởi người sử dụng chương trình.

• Bước hai của pipeline, thread thực thi bước này sẽ thiết lập k thread.

Tham số k được nhập vào từ người sử dụng chương trình Mỗi thread trong k thread này sẽ có nhiệm vụ xử lý từng chuỗi đọc trong tập các chuỗi đọc được từ dữ liệu tập tin fq Tham số k không nhất thiết phải có quan hệ gì với n Mỗi thread trong k thread sau đó sẽ thực hiện so trùng chuỗi nhận được với gen tham khảo và sắp hàng để đưa ra kết quả cuối cùng.

• Bước ba của pipeline đơn giản là thực hiện việc ghi dữ liệu đầu ra xuống tập tin sam.

Từ sơ đồ dòng chảy của chương trình, chúng tôi nhận thấy pipeline bước hai khi hiện thực giải thuật BWA-MEM trên CPU, đã có sử dụng multithread- ing Việc này chứng tỏ rằng ta có thể thay thế việc sử dụng multithreading trong bước này bằng việc tải dữ liệu lên để GPU xử lý rồi trả kết quả về choCPU.

CÁC CÔNG TRÌNH LIÊN QUAN

Tăng tốc với FPGA

Phiên bản đầu tiên được hiện thực bởi nhóm tác giả [17], nhóm tác giả đã phân tích chương trình gải thuật BWA-MEM ra làm ba phần kernel chính: SMEM Generation, Seed Extension and Output Generation Để xác định kernel nào phù hợp nhất cho việc tăng tốc giải thuật này, nhóm tác giả đã dùng gprof vàoprof Cả hai đều cho ra kết quả như nhau.Bảng 4.1 thể hiện kết quả phân tích chương trình BWA-MEM Dựa vào phân tích trên nhóm tác giả đã tăng tốc phần seed extension trên FPGA dưới dạng một mảng các đơn vị xử lí(Processing Elements) và các mảng này hoạt động song song Bên cạnh đó, kĩ thuật lập trình động (Dynamic Pogramming) rất phù hợp cho hiện thực trên nền tảng FPGA, do đó Seed Extension kernel được chọn để hiện thực quá trình tăng tốc Trong bài báo này [17], Seed Extension được hiện thực và thực thi trên nền tảng FPGA, quá trình SMEM Generation được thực thi trên CPU.

Bảng 4.1: Kết quả phân tích chương trình BWA-MEM

Programming Kernel Time Bottleneck Processing

SMEM Generation 56% Memory Parallel Seed Extension 32% Computation Parallel Output Generation 9% Memory Parallel

Các giai đoạn thực thi của hai quá trình này sẽ chồng chéo với nhau nhằm tối ưu thời gian, cũng như quá trình thực thi Giai đoạn cuối cùng là Output Generation sẽ được thực thi sau khi hai quá trình Seed Extension và SMEM Generation đã được thực thi xong hoàn toàn Trong Seed Extension, giải thuật Smith-Waterman là một giải thuật lập trình động (Dynamic Programming) nổi tiếng trong việc tìm kiếm sự tối ưu trong việc sắp xếp giữa hai chuỗi với nhau và cho ra điểm kết quả của việc tính toán Một ma trận tương tự như trong giải thuật Smith-Waterman được sử dụng trong BWA-MEM để đánh dấu những điểm số tốt nhất của quá trình tính toán, bao gồm: khớp, không khớp và khoảng cách (matches, mismatches and gaps) Giải thuật lập trình động sẽ được hiện thực trên hệ thống phần cứng tái cấu hình như là mộtmảng systolic(systolic array) tuyến tính Mảng systolic là mạng đồng nhất của các đơn vị xử lý dữ liệu được ghép chặt (DPUs: Data Processing Units) được gọi là các ô (cells) hoặc các nút (nodes) Mỗi nút hoặc DPU độc lập tính toán một phần kết quả như một hàm của dữ liệu nhận được từ các nút hoặc DPUs trước nó truyền vào, lưu trữ kết quả trong chính nó và truyền dữ liệu cho các nút hoặc DPUs tiếp theo mà đứng sau nó [25] Mỗi mảng systolic bao gồm nhiều phần tử xử lí (Processing Elements: PEs) thực thi song song, độc lập với nhau và mỗi phần tử xử lí sẽ đọc, xử lí từng kí tự một Hình 4.1 thể hiện mô hình hiện thực tăng tốc Seed Extension của [17] Có nhiều loại cấu hình PE-Module (Processing Element Module) trên FPGA như: mảng systolic chuẩn (standard systolic array), tùy biến độ dài vật lí (Variable Physical Length: VPL), tùy biến độ dài logic (Variable Logical Length: VLL) hoặc là PE-đơn giống như cấu trúc của GPU Hình 4.2 thể hiện các loại cấu hình của PE-Module.

Dựa vào các ưu điểm và nhược điểm của cấu hình PE-Modules trên FPGA,sự kết hợp giữatùy biến độ dài logic (VLL) vàtùy biến độ dài vật lí (VPL) tạo

Hình 4.1: Mô hình hiện thực tăng tốc Seed Extension của bài báo [17]

Hình 4.2: Cấu hình của PE-Module: (a) standard systolic array configura- tion;(b) Variable Logical Length configuration that can bypass part of the array; (c) Variable Physical Length configuration that matches systolic array length to read length; (d) GPU-like single-PE modules [17] thành Variable Logical and Physical Length (VLPL) đã được lựa chọn dựa trên hiệu suất tương đối của cấu hình PE-Module và các điểm tối ưu (được gọi là điểm thoát tối ưu hóa của cấu hình này) để hiện thực trong bài báo trên.

Bên cạnh đó, một hướng tiếp cận tăng tốc giải thuật BWA-MEM khác cũng được hiện thực và trình bày trong bài báo [26] SMEM Generation và Seed Extension được cải tiến để tăng tốc giải thuật BWA-MEM Có hai điểm cần cải thiện ở SMEM Generation:

1 Vì chiều dài tối thiểu yêu cầu luôn luôn lớn hơn kết quả của quá trình khớp chính xác (exact match) Do đó việc mở rộng ngược của hai khoảng thời gian bị bỏ qua và chỉ số FMD-index không bị lãng phí khi truy cập.

2 Trong khi tính toán SMEM, việc đánh dấu các khoảng thời gian của tất cả các chuỗi được lưu lại Các chuỗi là một chuỗi con và hằng số của chuỗi đầy đủ ngược của SMEM.

Với phương pháp này, tỉ lệ tổng số lần truy cập FMD-index nhỏ hơn giải thuật gốc lên đến 45% Bên cạnh việc tăng tốc phần mềm, tra cứu mảng hậu tố (suffix array lookup) và phần Seed Extension đã được triển khai trên nền tảng FPGA Khi tìm kiếm mảng hậu tố chạy trên CPU, phần lớn thời gian được dành để chờ bộ nhớ và mất khoảng 15% thời gian của toàn bộ ứng dụng Hình 4.3 thể hiện kiến trúc của tra cứu mảng hậu tố được hiện thực trên FPGA ở bài báo [26] Ý tưởng của việc trộn dữ liệu đầu vào và pipelining bộ nhớ đọc được áp dụng để tránh chờ đợi cho bộ nhớ Mô đun tăng tốc còn lại là Seed Extension, ý tưởng tương tự như [17] bằng cách sử dụng một mảng systolic bao gồm các phần tử xử lý (PE) hoạt động song song bên trong Một PE được ánh xạ ứng với một kí tự được đọc vào để xử lí, độ dài tối đa của một lần đọc được xác định bởi độ dài của mảng PE Mỗi chu kỳ, một ô của ma trận được xử lý bởi một PE và các giá trị kết quả được chuyển đến phần tử tiếp theo.

Hai phiên bản cải tiến trên đã có những cải tiến sau:

• Cài đặt ban đầu cho ma trận lập trình động (dynamic programming matrix) là những giá trị khác 0 Các điểm số của quá trình sắp xếp được tìm thấy từ SMEM generation sẽ tự quyết định giá trị của chính nó.

Hình 4.3: Kiến trúc của tra cứu mảng hậu tố [26]

• Cải thiện Output generation giữa các PEs.

• Không áp dụng heuristic để đạt được kết quả tốt hơn so với giải thuật gốc.

Như chúng ta đã thấy, giải thuật BWA-MEM có nhiều điểm có thể cải thiện thêm được nữa Ngoài hai bài báo đã trình bày trên, nhóm tác giả bài báo [27] đã trình bày một mô hình tăng tốc BWA-MEM trên nền tảng FPGA.

Trong bài báo này, ma trận Smith-Waterman sẽ được hiện thực trên nền tảng FPGA Hình 4.4 trình bày tổng quát mô hình hiện thực ở bài báo [27].

Hình 4.4: Kiến trúc của mô hình tăng tốc ma trận Smith-Waterman ở bài báo [27]

Các mảng PEs xử lí ma trận Smith-Waterman trên FPGA được kết nối với mộ bộ phân chia công việc (task distributor) Bộ phân chia công việc sẽ kết nối với bộ nhớ thông qua AXI (Advanced eXtensible Interface) bus Dựa vào mã nguồn của BWA-MEM, cấu trúc phần cứng của các PEs được tạo ra bởi phương pháp tổng hợp ở bậc cao (high-level synthesis methodology) Điều này giúp cho thời gian của hiện thực giảm đi đáng kể và nhanh hơn rất nhiều.

Có ba thành phần chính trong một mảng PE:

1 Bộ phân chia công việc sẽ nhận dữ liệu từ DRAM vào BRAM (Block Random Access Memory) và phân chia dữ liệu vào các PE thông qua các FIFO.

2 Các PE sẽ nhận dữ liệu từ các FIFO Mỗi PE sẽ tính toán một ma trận Smith-Waterman để tối ưu hóa thông lượng (throughput).

3 Các bộ thu thập kết quả (result collector) sẽ nhận dữ liệu được đẩy ngược trở lại FIFO từ các PE và đóng gói các dữ liệu này cho máy chủ (ở đây PC sẽ là máy chủ, FPGA sẽ là thiết bi). Để đánh giá kết quả, nhóm tác giả đã thiết kế để kế một wavefront trên FPGA Dựa vào wavefront này, nhóm tác giả đánh giá mối liên hệ giữa số lượng kernel (kí hiệu là nK ) và số lượng PE (kí hiệu làmP ) trên mỗi kernel

(kí hiệu chung là: mP xnK ) Trong trường hợp 1P x116K cho ra kết quả thử nghiệm tốt nhất).

Tăng Tốc với GPU

Nền tảng GPU được sử dụng khá rộng rãi trong các đề tài tăng tốc giải thuật nhờ vào ưu điểm song song hóa của bản thân Một phiên bản tăng tốc giải thuật BWA-MEM trên nền tảng GPU được hiện thực ở bài báo [28] Mô hình hiện thực ở bài báo này tương tự như hiện thực giải thuật BWA-MEM trênFPGA ở bài báo [17] Các mảng systolic được hiện thực trên nền tảng GPU thay vì trên nền tảng FPGA Bên cạnh đó, vấn đề cân bằng trong quá trình thực thi giữa CPU và GPU được cân nhắc trong bài báo này, và một chiến lược cân bằng tải (workload) giữa CPU và GPU được hiện thực nhằm tối ưu hóa thời gian hiện thực của toàn bộ chương trình Giải thuật này sẽ tối ưu hóa thời gian rảnh rỗi giữa CPU và GPU Quá trình này được điều khiển bởi một tham số gọi là Hệ số cân bằng tải (Load Balancing Factor: LBF), sau mỗi quá trình đọc dữ liệu thì giá trị của LBF sẽ được tính toán lại Mỗi nhân CUDA thực hiện tính toán được ánh xạ như là mỗi phần tử xử lí (PEs) Các luồng CUDA (CUDA thread) thực thi các lệnh giống nhau sẽ được kết hợp lại thành một khối bao gồm 32 luồng (gọi làWARP) Các PEs sẽ chia sẻ, trao đổi dữ liệu với nhau thông qua bộ nhớ chia sẻ cache trên cùng chip (on-chip Shared Memory cache) Trong đề tài này, kernel thực thi trên GPU được thiết kế và hiện thực trên mỗi WARP đơn, với độ dài cột tối đa 32-kí tự và một bộ WARP ở đây cũng được hiểu như là một PASS Sự trao đổi dữ liệu giữa các PASS thông qua bộ nhớ chia sẻ (shared memory), còn giữa các core với nhau thì sử dụng xáo trộn các lệnh thực thi (shuffle instructions) để tránh sử dụng bộ nhớ chia sẻ (shared memory) Trong hiện thực này, ma trận tương tự Smith-Waterman không khởi tạo giá trị 0 ban đầu Extend kernel tạo ra nhiều output hơn và heuristic được áp dụng để giới hạn sự tính toán lại trong ma trận tương tự này (Hình 4.5 thể hiện mô hình hiện thực của bài báo trên).

Hình 4.5: Mô hình hiện thực tăng tốc Seed Extension trên GPU của bài báo[28]

Trong công trình [28], nhóm tác giả đã loại bỏ việc sử dụng truy cập trao đổi dữ liệu giữa các PEs bằng cách sử dụng kĩ thuật xáo trộn lệnh thực thi (shuffle instructions) và đồng thời sử dụng CUDA Dynamic Parallelism chức năng điều khiển bên ngoài để giảm thanh ghi trong GPU Thay vì sử dụng nhiềuWARPtrên một GPU như bai báo [28], chính nhóm tác giả đã cải tiến cách thức hoạt động của Seed Extension của mình trên GPU trong công trình [21] Thay vào đó là chỉ duy nhất mộtPASS (WARP) được sử dụng Các PEs đầu tiên trongWARP sẽ đọc dữ liệu vào trongWARP và các PEs cuối sẽ ghi dữ liệu vào bộ nhớ để sử dụng cho lần kế tiếp ("Hình 4.5" thể hiện mô hình hiện thực của bài báo trên) VớiWARPđơn, một quy mô lớn kerel có thể

Hình 4.6: Mô hình hiện thực tăng tốc Seed Extension được cải tiến trên GPU của bài báo [21] được khởi tạo một cách nhanh chóng trên GPU Các hệ thống bộ nhớ chuyên dụng con trên GPU được sử dụng như một lợi thế cục bộ để đặt giá trị tham chiếu và dữ liệu đầu vào Do đó, chiều dài giá trị tham chiếu bị cắt ngắn, vì không cần thiết để xử lý một phần của ma trận tương tự.

puting)

Thiết bị thử nghiệm

Bảng 4.2 Liệt kê cấu hình máy chủ dùng để thực thi chương trình BWA-MEM của các nghiên cứu trên.

Bảng 4.2: Cấu hình phần cứng máy chủ (CPU-only)

Paper CPU Frequence(GHz) Number of Cores Cache(MB) RAM(DDR3)

[28] Intel Core i7-4790 4.0(Turbo Speed) 4 8 32 GB

Bảng 4.3 Liệt kê cấu hình thiết bị dùng để thực thi chương trình BWA-MEM của các nghiên cứu trên.

Bảng 4.3: Cấu hình phần cứng thiết bị

Paper FPGA GPU Number of devices

[28] Intel Core i7-4790 NVIDIA GeForce GTX TITAN X 2

[21] Intel Core i7-4790 NVIDIA GeForce GTX 970 1

Kết quả

Bảng 4.4 tổng hợp các kết quả tăng tốc đạt được so với trên CPU thuần của các công trình nghiên cứu đã nêu ở trên.

Bảng 4.4: Kết quả đạt được

THIẾT KẾ HỆ THỐNG

Hệ thống tổng quan

Dựa vào bảng phân tích trong bài báo [17], Seed Extension là phân đoạn có hàm lượng tính toán lớn nhất và chiếm 30%-40% thời gian thực thi của chương trình Trong đó, việc tính toán ma trận Smith-Waterman chiếm đa số trong phân đoạn này Do đó việc lựa chọn và tập trung vào chuyển hóa tính toán ma trận Smith-Waterman trong Seed Extension được lựa chọn thực thi trên GPU với mong muốn là có kết quả tốt hơn so với ban đầu Ở mã nguồn BWA-MEM gốc, ba bước gồm Seed Generation, Seed Extension và Output Generation được thực thi hoàn toàn trong bước hai của pipeline Ba bước này sẽ được áp dụng lên mỗi chuỗi đọc cần được so trùng và được thực thi với một thread trong kthread được khởi tạo từ thread chính.

1 Bước Seed Generation được thực thi trên CPU Các chuỗi seed được tạo ra sau khi hoàn tất bước này và các chuỗi này sẽ được chuyển cho bước Seed Extension.

2 Bước Seed Extension nhận dữ liệu từ Seed Generation và tính toán một số bước trong Seed Extension bằng CPU Sau đó dữ liệu này sẽ được chuẩn bị cho quá trình tính toán ma trận Smith-Waterman trên GPU.

Hình 5.1: Mô hình hiện thực tăng tốc ma trận Smith-Waterman trên GPU

3 Quá trình tính toán ma trận Smith-Waterman cho phần Left Extension sẽ được thực thi trên GPU.

4 Sau khi tính toán xong ma trận Smith-Waterman, kết quả sẽ được trả về từ GPU (Nếu kết quả không thỏa thì quá trình tính toán ở Bước 3 có thể được thực hiện lại lần nữa để có thể có được kết quả tốt hơn) Dữ liệu mới để tính toán ma trận trong quá trình Right Extension sẽ được chuẩn bị và chuyển cho GPU.

5 Quá trình tính toán ma trận Smith-Waterman cho phần Right Extension sẽ được thực thi trên GPU.

6 Cuối cùng, host nhận được kết quả (nếu kết quả không thỏa thì quá trình tính toán ở Bước 5 có thể được thực hiện lại lần nữa để có thể có được kết quả tốt hơn), tổ chức lại dữ liệu và tiếp tục thực thi các giai đoạn xử lý sau của giải thuật BWA-MEM.

Cấu trúc dữ liệu nhiều lớp

Cấu trúc dữ liệu nhiều lớp (Nested Data Structure) là cấu trúc dữ liệu có phần tử là con trỏ hay mảng của một cấu trúc dữ liệu nhiều lớp khác tạo thành nhiều tầng dữ liệu khác nhau Cấu trúc dữ liệu nhiều lớp được sử dụng phổ biến trong lập trình phần mềm và nhiều ứng dụng khác vì nó cung cấp khả năng tổ chức dữ liệu và thể hiện được mối quan hệ giữa các dữ liệu khác nhau trong chương trình Đặc biệt trong mã nguồn C của BWA-MEM, cấu trúc dữ liệu nhiều lớp cũng được tác giả sử dụng gần như xuyên suốt cả chương trình.

Tuy nhiên, việc sử dụng cấu trúc dữ liệu nhiều lớp để thể hiện dữ liệu lại gây khó khăn cho việc sử dụng CUDA để xử lý dữ liệu Trong ngôn ngữ CUDA, để chúng ta có thể đưa một lượng dữ liệu từ Host memory (RAM) lên Device memory (bộ nhớ của GPU) thì ta phải thực hiện ít nhất hai bước như sau:

1 Host (CPU) khai báo một con trỏ thuộc sở hữu của Device (GPU) Con trỏ của Device được cấp phát bằng lệnh CUDA API cudaMalloc Host không có quyền truy cập hay không có khả năng truy cập lượng bộ nhớ mà con trỏ Device trỏ đến.

2 Host gọi lệnh CUDA API cudaMemcpyvới đầu vào là con trỏ Device, con trỏ Host trỏ đến dữ liệu cần sao chép lên Device memory, kích thước của dữ liệu tính theo byte và hướng truyền dữ liệu từ Host đến Device.

Tuy nhiên, trong thực tế, dữ liệu ta muốn sao chép lên Device memory không phải lúc nào cũng là mảng dữ liệu một chiều mà còn có thể là cấu trúc dữ liệu nhiều lớp (trong trường hợp đề tài này) Cụ thể hơn, ta xét một cấu trúc dữ liệu nhiều lớp điển hình là đầu vào của kernel CUDA ở Hình 5.1 Dữ liệu đầu vào của GPU là một mảng n phần tử từ mem_chain_v với n là số lượng chuỗi đọc vào từ pipeline bước 1 Hình 3.5.

Listing 5.1: Sao chép mảng h_chains vào d_chains mem_chain_t *d_chains; cudaMalloc(&d_chains, n * sizeof(mem_chain_t)); cudaMemcpy(d_chains, h_chains, n * sizeof(mem_chain_t), cudaMemcpyHostToDevice);

Nếu thực hiện tác vụ như 5.1 thì chúng ta sẽ không nhận được kết quả như mong muốn do chỉ có nội dung của biến con trỏ a của mem_chain_v tức là địa chỉ của vùng nhớatrỏ vào là được sao chép lên Device memory chứ vùng nhớ màatrỏ đến không hề được sao chép lên cùng Ta có thể tham khảo cách sao chép một cấu trúc dữ liệu hai lớp từ bộ nhớ Host lên bộ nhớ Device trong phụ lục A.3 Tuy nhiên, cách làm của A.3, ta chỉ có thể sao chép thành công một cấu trúc dữ liệu hai lớp lên bộ nhớ Device Đối với dữ liệu ba lớp như mem_chain_v, việc sao chép lên là phức tạp hơn nhiều và có thể không thực hiện được Trong cộng đồng lập trình viên CUDA, việc sử dụng cấu trúc dữ liệu quá nhiều lớp (từ ba lớp trở lên) là không được khuyến khích do việc truy xuất vào dữ liệu mang cấu trúc này không phù hợp với phương cách truy xuất bộ nhớ của GPU Chúng tôi đề cử phương án sử dụng index để gom cụm và sao chép dữ liệu Ta bỏ qua sự có mặt của con trỏ trong cấu trúc dữ liệu nhiều lớp, gom cụm tất cả các mem_chain_v thành một mảng, tương tự với mem_chain_t và mem_seed_t (Hình 5.2) Khi đó vấn đề nảy sinh là làm thế nào để biết được mem_seed_t nào thuộc mem_chain_t nào và mem_chain_t nào thuộcmem_chain_v nào?

Hình 5.2: Ví dụ về một đoạn dữ liệu trong tập tin FASTQ Để sao chép 5 mảng trong Hình 5.2, ta thực hiện theo cách thông thường như Hình 5.1 Việc nối các phần tử của mảng lại trở thành cấu trúc dữ liệu nhiều lớp như ban đầu được thực hiện đơn giản như ví dụ sử dụng các mũi tên trong Hình 5.2 tượng trưng cho việc các con trỏ gán lại các địa chỉ phù hợp Mã nguồn CUDA để khôi phục dữ liệu nhiều lớp có thể được tham khảo trong phục lục A.4 Đầu ra của Seed Extension Kernel là cấu trúc dạng nhiều lớp nên được sao chép từ bộ nhớ Device về bộ nhớ Host bằng cách tương tự.

Bên cạnh đó, CUDA không hỗ trợ một số hàm built-in của C Mã nguồn C gốc của bước Seed Extension nếu muốn sử dụng lại trong CUDA thì phải thay đổi để phù hợp với ngữ pháp của CUDA Vì Seed Extension là bước có hàm lượng tính toán lớn nên các hàm built-in của C được sử dụng không nhiều.

CUDA có phiên bản của các hàm malloc hay memset của riêng mình nhưng các hàm nhưcallocvàreallocthì không được hỗ trợ Tuy nhiên, vớimallocvà memset, người lập trình hoàn toàn có thể làm ra phiên bản calloc và realloc của riêng họ Đối với các hàm còn lại, nhóm chúng tôi làm một bản sao của chúng mà thực hiện một số sửa đổi để trở thành mã nguồn mà Device có thể gọi được Những sửa đổi đó có thể là thêm device vào khái báo tên hàm để biểu thị đây là hàm chỉ device mới được gọi hay lược bỏ đi các hàm built-in không sử dụng được và thay vào đó phiên bản chúng tôi tự lập trình, v v.

HIỆN THỰC HỆ THỐNG

Hiện thực Smith-Waterman kernel trên GPU

Trong Seed Extension, ma trận tính điểm Smith-Waterman là một khâu tính toán quan trọng Với dữ liệu đầu vào là hai chuỗi gen có độ dài tùy ý cùng với nhưng tham số về điểm phạt khoảng cách, ma trận thay thế, ma trận tính điểm Smith-Waterman sẽ trả về kết quả là một chuỗi trùng lắp với hai chuỗi gen đầu vào với số điểm cao nhất Trong phần này, nhóm chúng tôi sẽ đánh giá sự phụ thuộc dữ liệu khi tính toán các phần tử trong ma trận và đưa ra phương án để tính toán song song ma trận này Ta có thể khái quát một cách đơn giản ma trận Smith-Waterman như trong Hình 6.1 với m và n tương ứng là độ dài của hai chuỗi gen đầu vào, X tượng trưng cho ô có giá trị khởi tạo từ đầu hoặc đã biết Trên CPU, ma trận tính điểm sẽ được tính từ trái sang phải và từ trên xuống dưới Với hai chuỗi có độ dàimvànthì độ phức tạp của giải thuật Smith-Waterman khi thực thi tuần tự sẽ là:

O(m×n)Dựa vào Hình 2.8, ta có thể quan sát thấy rõ giá trị của ô góc dưới bên phải phụ thuộc vào giá trị của ô góc trên bên phải và các ô ở phía trái Xét trên tổng thể toàn bộ ma trận Smith-Waterman, các ô nằm bên trong ma trận thì

Hình 6.1: Ma trận Smith-Waterman đơn giản sẽ có sự phụ thuộc dữ liệu như ô góc dưới bên phải của Hình 2.8 còn các ô ở biên trên và trái của ma trận sẽ chỉ phụ thuộc vào giá trị của ô đằng trên nó.

Từ dữ kiện này, các ô nằm trên cùng một đường chéo có thể được tính toán song song Dựa vào Hình 6.2, thời gian tính toán hết hàng đầu tiên của ma trận sẽ là n đơn vị thời gian Cứ sau một đơn vị thời gian, sẽ có thêm một hàng của ma trận được hoàn thành Vậy, ta cần thêmm −1đơn vị thời gian để tính toán hết các hàng còn lại Độ phức tạp của giải thuật Smith-Waterman khi thực thi song song sẽ là:

O(m+ n)Tuy độ phức tạp của giải thuật Smith-Waterman khi thực thi song song tốt hơn tuần tự nhiều nhưng trong thực tế đề tài của chúng tôi, hai cách này sẽ được thực nghiệm trên hai hệ thống khác nhau (GPU và CPU) nên tốc độ chạy còn phụ thuộc vào nhiều yếu tố khác ngoài độ phức tạp Thay vì quan sát theo phương diện tính toán cùng lúc các ô trên cùng một đường chéo nhưHình 6.2, ta xét theo từng hàng của ma trận GọiT là thời gian tính toán một ô phần tử của ma trận Ta sắp đặt mỗi thread sẽ đảm nhiệm tính toán các phần tử trên cùng một hàng của ma trận Bằng cách này, hàng dưới sẽ tính toán chậm hơn hàng trên một chu kỳ T, nhận kết quả đầu ra của hàng trên và sử dụng lại chính kết quả của cột mà thread mỗi hàng đã tính phía trước để tính toán cho phần tử ở cột tiếp theo Tuy nhiên, để có thể hiện thực ý tưởng ởHình 6.3 ta cần phải chú ý đến các vấn đề sau đây:

Hình 6.2: Các bước tính toán song song ma trận Smith-Waterman

Hình 6.3: Minh họa đơn giản cách các Thread tính toán ma trận Smith- Waterman

• Các Thread sử dụng cách nào để trao đổi dữ liệu với nhau?

• Liệu có xảy ra vấn đề về tranh chấp tài nguyên dùng giữa các Thread hay không và làm sao để hiện thực các vùng tranh chấp?

• Làm thế nào để các Thread có thể thực hiện được đúng thứ tự mong muốn như Hình 6.3 trong khi cách Thread chạy là không đoán trước được. Đối với vấn đề trao đổi dữ liệu giữa các Thread với nhau, sau quá trình tìm hiểu, nhóm chúng tôi đề ra hai cách: Cách thứ nhất đó là sử dụng Shuffle và cách thứ hai đó là sử dụng Shared Memory.

Shuffle là lệnh cung cấp khả năng cho Thread này đọc bộ nhớ thanh ghi giành riêng của Thread khác Đọc và ghi lên thanh ghi được coi là tác vụ đọc ghi bộ nhớ nhanh nhất của GPU Tuy nhiên việc sử dụng Shuffle có thể gây một số khó khăn cho người lập trình Shuffle chỉ có phạm vi ứng dụng hẹp,trong một warp (32 Threads) Các Thread trong cùng một Warp có đặc điểm là chúng thực thi lệnh theo lockstep Lockstep có nghĩa là nếu một Thread trong Warp thực thi xong một lệnh thì nó sẽ đợi tất cả các Thread hoàn thành lệnh này trước khi đọc và thực thi lệnh tiếp theo Nếu Warp này bắt gặp rẽ nhánh (if/else) thì các nhánh sẽ được thực hiện tuần tự, các Thread thuộc nhánh đang xếp hàng sẽ được GPU cho ngủ Vì vậy, Shuffle không thể thực hiện được giữa các Thread khác nhánh mặc dù chúng thuộc cùng một Warp, điều này có thể gây khó khăn cho việc lập trình.

Mặt khác, cách sử dụng Shared Memory thì đơn giản hơn Shared Mem- ory là bộ nhớ dùng chung của các Thread trong cùng một Block nên chỉ các Thread thuộc cùng một Block mới có thể truy cập bộ nhớ này Cũng chính vì đặc điểm này, ta cần chú ý trong việc sử dụng Shared Memory để tránh sự tranh chấp tài nguyên giữa các Thread Nhóm chúng tôi đã sử dụng các hàm atomic của CUDA để hiện thực vùng tranh chấp (tham khảo ở A.5).

Ngoài ra, syncthreads() - hàm cung cấp khả năng dừng tất cả Thread trong cùng một Block ở điểm nó được gọi cho đến khi tất cả các Thread đến nơi, được nhóm chúng tôi sử dụng để phân chia hai giai đoạn đọc và xử lý dữ liệu, ghi dữ liệu Điều này đảm bảo các Thread luôn kịp xử lý dữ liệu mình nhận được trước khi dữ liệu này bị ghi đè bởi dữ liệu nhận được ở chu kỳ tính toán tiếp theo.

Chúng tôi lựa chọn sử dụng Shared Memory để trao đổi dữ liệu giữa cácThread bới so với thanh ghi, tuy thời gian truy xuất bộ nhớ có chậm hơn,nhưng vẫn thuộc loại nhanh và được khuyến khích sử dụng trong các loại bộ nhớ của GPU.

KẾT QUẢ THỰC NGHIỆM

Môi trường thực nghiệm

Bộ công cụ CUDA có hỗ trợ chương trình để kiểm tra tính sẵn sàng và đưa ra các thông số của thẻ đồ họa mà hệ thống của chúng ta đang sử dụng. cuda/samples/1_Utilities/deviceQuery Khi ta chạy chương trình này với hệ thống sử dụng NVIDIA GeForce 940Mthì thu được báo cáo như sau:

• CUDA Driver Version / Run Time Version: 9.0 / 8.0

• CUDA Capability Major/Minor version number: 5.0, hay còn thường được gọi là Compute Capability của thẻ đồ họa Con số này phân loại các thẻ đồ họa, quy định các thông số khác của thẻ đồ họa, tính năng nào thẻ đồ họa hỗ trợ.

• Total amount of global memory: 2003 Mbytes 2Mbytes là con số mặc định chỉ dung lượng của bộ nhớ toàn cục mà mỗi chương trình CUDA được phép sử dụng Dung lượng của bộ nhớ toàn cục có thể được thay đổi bằng cách sử dụng lệnh CUDA cudaDeviceSetLimit với tham số thứ nhất là cudaLimitMallocHeapSize.

• (3) Multiprocessors, (128) CUDA Cores/MP: 384 CUDA Cores.

• GPU Max Clock rate: 1176 MHz (1.18 GHz).

• Total amount of constant memory: 65536 bytes.

• Total amount of shared memory per block: 49152 bytes.

• Total number of register available per block: 65536 Người lập trình không được toàn quyền kiểm soát bộ nhớ thanh ghi mà chỉ có thể đặt giới hạn cho nó sử dụng –maxrregcount= trong câu lệnh dịch chương trìnhnvcc Thông thường, số lượng thanh ghi mà mỗi Thread sẽ sử dụng sẽ được chương trình dịch tính toán trước, ta có thể xem thông số này bằng cách sử dụng –ptxas trong lệnh dịch chương trìnhnvcc Số lượng thanh ghi mà mỗi Thread sử dụng càng nhiều thì số lượng Thread mà một Block có thể chứa càng ít.

• Maximum number of threads per multiprocessor: 2048.

• Maximum number of thread per block: 1024 Con số này là tích lớn nhất của số Thread trên mỗi phương x, y, z của Block.

• Max dimension size of a thread block (x, y, z): (1024, 1024, 32)

Chương trình BWA-MEM gốc sẽ được chạy Multithreading và lấy số liệu trên Intel Core i3-5010U.

• Tần số cơ sở của bộ xử lý: 2.10 GHz

Vậy nên, chương trình chạy trên Intel Core i3-5010U có thể được thực thi tối ưu trên 4 Threads luận lý.

Dữ liệu đầu vào của BWA-MEM là tập các chuỗi gen thô (FASTQ) và tập các chuỗi gen tham khảo (FASTA) Định dạng tệp tin của FASTQ và FASTA đã được nói rõ trong phần 3.2.1 Gen tham khảo mà nhóm sử dụng để thực nghiệm trong đề tài là Hg19 Chromosome - một trong các bộ gen tham khảo của gen người Kích thước của gen tham khảo này xấp xỉ 3.3 GBytes Ngoài ra, ta có thể tải về để thử nghiệm với các bộ gen tham khảo khác từ cơ sở dữ liệu mở của Trung tâm Thông tin Công nghệ sinh học Quốc Gia trực thuộc Thư viện Y học Quốc gia Hoa Kỳ, trực thuộc Viện Y tế Quốc gia Hoa Kỳ [1].

Ngoài ra, tập các chuỗi gen thô còn có thể được tạo ra bằng cách mô phỏng từ chuỗi gen tham khảo bất kỳ và đây cũng là cách mà nhóm chúng tôi sử dụng để có thể thu được tập các chuỗi gen thô có độ dài khác nhau Công cụ hỗ trợ việc mô phỏng tập các chuỗi gen thô có tên NEAT-genreads, có mã nguồn được chia sẻ mở trên GitHub [31] Cách sử dụng công cụ này đã được tác giảZachary Stephens hướng dẫn kỹ lưỡng trong README.md của Repository này.

Cách thức thực nghiệm

7.2.1 Chọn dữ liệu đầu vào cho BWA-MEM với Smith-Waterman

Kernel

Cách đánh giá kết quả thực nghiệm

Ngoài việc quan sát đồ thị để đánh giá kết quả thực nghiệm, nhóm chúng tôi đồng thời cũng phân tích hiệu suất của chương trình CUDA thực tế của hai phương án hiện thực và giải thích kết quả thực nghiệm nhận được.

NVIDIA cung cấp công cụ NVIDIA Visual Profiler để hỗ trợ người lập trình phân tích những yếu tố có thể giới hạn hay làm giảm hiệu suất của CUDA Kernel.

• Yếu tố giới hạn băng thông bộ nhớ.

• Yếu tố giới hạn tính toán.

• Yếu tố giới hạn độ trễ.

Giới hạn băng thông bộ nhớ có thể xảy ra do truy xuất bộ nhớ không hiệu quả, số lượng thanh ghi không đủ để đáp ứng cho Thread dẫn đến việc tràn ra bộ nhớ cục bộ hay việc sử dụng quá nhiều các biến Stack - các biến này cũng được lưu trữ trong bộ nhớ cục bộ Bộ nhớ cục bộ là một phần của bộ nhớ toàn cục nhưng nó là dành riêng cho mỗi Thread.

Ví dụ về việc truy xuất bộ nhớ không hiệu quả là việc đọc giá trị của mảng các cấu trúc dữ liệu, hay khi các Thread trong cùng một Warp cùng đọc một biến Giả sử một chu kỳ đọc dữ liệu Warp đọc lên 128 bytes kề nhau.

Trong hình 7.1, dữ liệu có ích cho Warp chỉ là 32×3 = 96 bytes nhưngWarp đã phải thực hiện ba chu kỳ đọc 128 bytes do ba biến 32 bytes không

Hình 7.1: Các Thread trong Warp cùng đọc biến a của mảng các cấu trúc dữ liệu được sắp xếp gần nhau Việc này dẫn đến hiệu quả đọc bộ nhớ chỉ đạt 25%.

Vấn đề tương tự xảy ra ở hình 7.2

Hình 7.2: Các Thread trong Warp cùng đọc biến a

Yếu tố giới hạn tính toán chủ yếu là do sự phân kỳ tạo ra bới các câu lệnh rẽ nhánh (Divergent Branches) Các Thread trong cùng một Warp thực thi theo Lockstep, tức là chúng sẽ cùng nhau thực thi từng lệnh một mà không có Thread nào nhanh hơn Thread nào Tuy nhiên, khi gặp câu lệnh rẽ nhánh, từng nhánh sẽ được thực hiện tuần tự Thread nào thuộc nhánh đang ở trong hàng đợi thì sẽ được ngủ (Hình 7.3) Tuy nhiên, nếu mỗi nhánh là dành riêng cho các Warp khác nhau thì điều này sẽ không xảy ra (Hình 7.4).

Hình 7.3: Các nhánh của if/else được thực hiện tuần tự

Hình 7.4: if/else áp dụng trên 2 Warp khác nhau

Yếu tố giới hạn độ trễ được quyết định bởi:

• Độ lấp đầy của Multiprocessor lý thuyết (Theory Occupancy) là thương của số Warp mà Kernel có thể mở được và số Warp tối đa một MP có thể chứa Số Warp mà Kernel có thể mở được sẽ bị giới hạn cận trên bởi số thanh ghi một Thread sử dụng và số dung lượng bộ nhớ chia sẻ mỗi Block sử dụng Trong thực tế, Achieved Occupancy sẽ được tính toán theo công thức khác.

• Nếu Kernel mở quá ít Block thì hiệu suất khai thác tài nguyên của GPU không cao do sẽ có MP không được phân công bất kỳ Block nào.

Bên cạnh đó, việc chuyển đổi nền tảng thực thi từ CPU sang GPU cũng đòi hỏi chi phí thực thi như:

• Khởi tạo hoặc hủy vùng dữ liệu trên GPU.

• Khởi tạo giá trị ban đầu cho vùng dữ liệu trên GPU.

• Di chuyển dữ liệu giữa CPU và GPU (host và device).

Nếu dữ liệu đầu vào cố định thì ta có thể cấp phát một lần và tái sử dụng một cách hợp lí Nhưng nếu dữ liệu đầu vào không cố định, dẫn đến việc quá trình khởi tạo lặp đi lặp lại nhiều lần sẽ ảnh hưởng rất lớn đến thời gian thực thi chương trình Mặc dù được DMA hỗ trợ chuyển dữ liệu từ CPU sangGPU (host sang device) nhằm tăng tốc tối đa hiệu quả và tiết kiệm thời gian chuyển dữ liệu nhưng việc gọi quá trình này thông qua các API (ApplicationProgramming Interface) cũng tốn rất nhiều thời gian cho quá trình này Mặc khác số lượng khối (block), threads (luồng) mỗi khối và chiều (dim) cũng ảnh hưởng đáng kể đến quá trình khởi tạo kernel để chạy trên GPU, nếu các thông số trên càng lớn và số lần gọi càng nhiều trong mỗi chương trình thì thời để khởi tạo càng lớn Đồng nghĩ với việc tổng thời gian thực thi chương trình của chúng ta càng tăng Do đó, đây cũng chính là một trong những "nút thắt cổ chai" (bottleneck) cần phải được cân nhắc và giải quyết một cách hiệu quả.

CPU thuần và CPU kết hợp GPU

kernel giữa CPU và GPU

Đánh giá kết quả

7.5.1 Toàn bộ chương trình BWA-MEM

Dựa vào mô hình thiết kế tăng tốc giải thuật ở Chương 5, chúng tôi nhận thấy rằng quá trình truyền nhận dữ liệu giữa CPU và GPU vô tình tạo ra bottleneck trong quá trình truyền nhận dữ liệu cũng như là quá trình khởi tạo ban đầu cho GPU Để kiểm chứng những nhận định trên, chúng tôi sử dụng NVIDIA Visual Profiler thu thập thông tin và phân tích kết quả đạt được Hình 7.7 hiển thị kết quả phân tích các API được sử dụng cho GPU trong chương trình BWA-MEM với dữ liệu đầu vào là 100bp.

Như ta thấy ở Hình 7.7, hàm cudaMalloc được gọi 27393 lần, thời gian tối thiểu hoàn thành là 6.1200às, thời gian tối đa để hoàn thành là 222.66ms,tớnh trung bỡnh lại là khoảng 18.570às, tổng thời gian thực thi trong chương

Hình 7.7: Kết quả phân tích quá trình gọi các Runtime API của CUDA bằng nvprof. trình là 508.71ms và chiếm khoảng 28.26% tổng thời gian gọi của các hàm Runtime API Tương tự, ta cũng có kết quả tổng hợp tương ứng với các hàm còn lại Nếu ta tính tổng lại tất cả các thời gian trên thì kết quả tương đối lớn (khoảng 2s đến 3s) so với toàn bộ chương trình thực thi là 5s (đối với 100bp).

Mặt khác, bởi vì quá trình thực hiện tính toán ma trận Smith-Waterman tiếp theo phụ thuộc vào điểm (score) mà quá trình tính toán trước đó trả về, vấn đề này dẫn đến phụ thuộc dữ liệu Cho nên dẫn đến mô hình chưa tối ưu hóa được quá trình pipeline giữa CPU và GPU, điều này tạo nên lỗ hổng thời gian do CPU chờ dữ liệu từ GPU Nếu quá trình hiện thực trên GPU tương đối tốt thì thời gian chờ sẽ giảm xuống đáng kể, tuy nhiên vấn đề này vẫn ảnh hưởng đến thời gian đạt được sau khi thực thi chương trình Nếu dữ liệu càng lớn thì số lần chờ càng nhiều dẫn đến kết quả cho ra thời gian sẽ càng cao.

Với tốc độ xử lí trung bình 2.1Ghz, khoảng gấp đôi so với GPU 940M (1 GHz), nhưng GPU lại có lợi thế trong xử lí và tính toán song song so với CPU Điều đó có lợi trong việc sử dụng GPU cho Dynamic Programming (DP) Tuy nhiên, kết quả thử nghiệm thể hiện ở Hình 7.6 lại không mang lại kết quả như mong đợi Dựa vào kết quả đạt được từ NVIDIA Visual Profiler mà chúng tôi đã dùng để phân tích hiệu suất của kernel thực thi trên GPU. Đây là các nguyên nhân gây ra hiệu suất thấp ở kernel:

• Chỉ số đọc bộ nhớ toàn cục (Global Memory Load Efficiency) chỉ đạt trung bình 57.6% (kernel sử dụng chỉ 2.1% tổng dung lượng bộ nhớ).

• Chỉ số ghi bộ nhớ toàn cục (Global Memory Store Efficiency) chỉ đạt trung bình 12.5%.

• Chỉ số chia sẻ bộ nhớ (Shared Memory Efficiency) chỉ đạt trung bình 29.2%.

• Kernel có quá nhiều các câu lệnh rẽ nhánh, dẫn đến Warp Execution Efficiency thấp: trung bình là 39.7%.

• Độ lấp đầy các Multiprocessor thấp (3.4%) do Kernel chỉ sử dụng tối đa một Block với 1024 Thread.

Qua các chỉ số trên, ta thấy việc sử dụng tài nguyên của GPU chưa được hiệu quả để tối ưu trong quá trình tăng tốc tính toán Smith-Waterman Để tìm hiểu kĩ nguyên nhân hơn, chúng tôi đã phân tích độ dài và rộng của dữ liệu đầu vào, hay nói đúng hơn là kích thước ma trận Smith-Waterman Ví dụ ở đây chúng tôi kiểm tra kích thước ma trận Smith-Waterman với dữ liệu đầu vào là 100bp Kết quả cho ra là không cố định đối với chiều dài và chiều rộng của ma trận Trường hợp xấu nhất là ma trận có kích thước (hàng x cột) (76 x 1), trong trường hợp này thì ma trận chúng ta cần tính tương đương với mảng một chiều và CPU mất khoảng 3às để hoàn thành tớnh toỏn, trong khi đú GPU cần hơn 4às hoàn thành (do phụ thuộc dữ liệu giữa cỏc Thread và quá trình chờ các Thread đồng bộ với nhau) Cho nên dữ liệu đầu vào cũng ảnh hưởng ít nhiều đến thời gian thực thi của kernel, cũng như kĩ năng lập trình tối ưu ma trận Smith-Waterman trên nền tảng GPU.

Ngày đăng: 09/09/2024, 00:38

Nguồn tham khảo

Tài liệu tham khảo Loại Chi tiết
[1] ncbi.nlm.nih.gov, “National center for biotechnology information,”https://www.ncbi.nlm.nih.gov/, 2017 Sách, tạp chí
Tiêu đề: National center for biotechnology information
[2] J. Quinlan, Y. Idaghdour, J.-P. Goulet, E. Gbeha, T. de Malliard, V. Bruat, J.-C. Grenier, S. Gomez, A. Sanni, M. C. Rahimy, and P. Awadalla, “Genomic architecture of sickle cell disease in west african children,” in Front. Genet., 2014 Sách, tạp chí
Tiêu đề: Genomic architecture of sickle cell disease in west africanchildren,” in "Front. Genet
[3] M. News, “Biologists’ new peptide could fight many cancers,” http://news.mit.edu/2018/peptide-could-fight-many-cancers-0115, 2018 Sách, tạp chí
Tiêu đề: Biologists’ new peptide could fight many cancers
[5] H. Li, “Aligning sequence reads, clone sequences and assembly contigs with bwa-mem,” arXiv preprint arXiv:1303.3997, 2013 Sách, tạp chí
Tiêu đề: Aligning sequence reads, clone sequences and assembly contigswith bwa-mem,” "arXiv preprint arXiv:1303.3997
[6] B. Langmead and S. Salzberg, “Fast gapped-read alignment with bowtie 2,” Nature Reviews Clinical Oncology, vol. 9, pp. 357–359, 2012 Sách, tạp chí
Tiêu đề: Fast gapped-read alignment with bowtie2,”"Nature Reviews Clinical Oncology
[7] Y. Liu and B. Schmidt, “Long read alignment based on maximal exact match seeds,” in Bioinformatics, 2012 Sách, tạp chí
Tiêu đề: Long read alignment based on maximal exactmatch seeds,” in "Bioinformatics
[8] S. Marco-Sola, M. Sammeth, R. Guigó, and P. Ribeca, “The gem map- per: fast, accurate and versatile alignment by filtration,” Nature methods, vol. 9, no. 12, p. 1185, 2012 Sách, tạp chí
Tiêu đề: The gem map-per: fast, accurate and versatile alignment by filtration,”"Nature methods
[9] S. Misra, A. Agrawal, W. keng Liao, and A. N. Choudhary, “Anatomy of a hash-based long read sequence mapping algorithm for next generation dna sequencing,” Bioinformatics, vol. 27 2, pp. 189–95, 2011 Sách, tạp chí
Tiêu đề: Anatomy ofa hash-based long read sequence mapping algorithm for next generationdna sequencing,”"Bioinformatics
[12] P. Ferragina, G. Manzini, V. M¨akinen, and G. Navarro, “An alphabet- friendly fm-index,” in String Processing and Information Retrieval.Springer, 2004, pp. 228–228 Sách, tạp chí
Tiêu đề: An alphabet-friendly fm-index,” in "String Processing and Information Retrieval
[13] P. Ferragina and G. Manzini, “Opportunistic data structures with appli- cations,” in Foundations of Computer Science, 2000. Proceedings. 41st Annual Symposium on. IEEE, 2000, pp. 390–398 Sách, tạp chí
Tiêu đề: Opportunistic data structures with appli-cations,” in "Foundations of Computer Science, 2000. Proceedings. 41stAnnual Symposium on
[14] T. F. Smith and M. S. Waterman, “Identification of common molecular subsequences,” Journal of molecular biology, vol. 147, no. 1, pp. 195–197, 1981 Sách, tạp chí
Tiêu đề: Identification of common molecularsubsequences,” "Journal of molecular biology
[15] W. contributors, “Smith–waterman algorithm — wikipedia, the free encyclopedia,” 2017, [Online; accessed 01-December-2017]. [On- line]. Available: https://en.wikipedia.org/w/index.php?title=Smith%E2%80%93Waterman_algorithm&amp;oldid=812335646 Sách, tạp chí
Tiêu đề: Smith–waterman algorithm — wikipedia, the freeencyclopedia
[16] H. Tom’s, “Office 2010 to make itself faster with your gpu,” https://www.tomshardware.com/news/office-2010-word-powerpoint-gpu,10447.html, 2010 Sách, tạp chí
Tiêu đề: Office 2010 to make itself faster with your gpu
[17] K. B. Ernst Joachim Houtgast, Vlad Mihai Sima and Z. Al-Ars, “An fpga-based systolic array to accelerate the bwa-mem genomic mapping algorithm,” in Embedded Computer Systems: Architectures, Modeling, and Simulation (SAMOS), 2015 International Conference on. IEEE, 2015, pp. 221–227 Sách, tạp chí
Tiêu đề: Anfpga-based systolic array to accelerate the bwa-mem genomic mappingalgorithm,” in "Embedded Computer Systems: Architectures, Modeling,and Simulation (SAMOS), 2015 International Conference on
[18] H. Li, “Exploring single-sample snp and indel calling with whole- genome de novo assembly,” Bioinformatics, vol. 28, no. 14, pp. 1838–1844, 2012 Sách, tạp chí
Tiêu đề: Exploring single-sample snp and indel calling with whole-genome de novo assembly,” "Bioinformatics
[19] M. Burrows and D. J. Wheeler, “A block-sorting lossless data compres- sion algorithm,” 1994 Sách, tạp chí
Tiêu đề: A block-sorting lossless data compres-sion algorithm
[20] W.-K. Sung, Algorithms in bioinformatics: A practical introduction.CRC Press, 2009 Sách, tạp chí
Tiêu đề: Algorithms in bioinformatics: A practical introduction
[21] K. B. Ernst Joachim Houtgast, Vlad-Mihai Sima and Z. Al-Ars, “An ef- ficient gpu-accelerated implementation of genomic short read mapping with bwamem,” ACM SIGARCH Computer Architecture News, vol. 44, no. 4, pp. 38–43, 2017 Sách, tạp chí
Tiêu đề: An ef-ficient gpu-accelerated implementation of genomic short read mappingwith bwamem,” "ACM SIGARCH Computer Architecture News
[22] A. W. T. F. J. R. N. H. G. M. G. A. R. D. Heng Li, Bob Handsaker, “The sequence alignment/map format and samtools,” Bioinformatics, vol. 25, no. 16, pp. 2078–2079, 2009 Sách, tạp chí
Tiêu đề: Thesequence alignment/map format and samtools,”"Bioinformatics
[25] W. contributors, “Systolic array,” 2018, [Online; accessed 01-June- 2018]. [Online]. Available: https://en.wikipedia.org/wiki/Systolic_array Sách, tạp chí
Tiêu đề: Systolic array

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w