Chip lập trình xử lý đồ họa

ĐẠI HỌC QUỐC GIA HÀ NỘI

TRƯỜNG ĐẠI HỌC CÔNG NGHỆ

HOÀNG ĐÌNH THẮNG

LẬP TRÌNH SONG SONG TRÊN
NỀN ĐƠN VỊ XỬ LÝ ĐỒ HỌA VÀ
ỨNG DỤNG

LUẬN VĂN THẠC SĨ

Hà Nội – 2010

ĐẠI HỌC QUỐC GIA HÀ NỘI
TRƯỜNG ĐẠI HỌC CÔNG NGHỆ

HOÀNG ĐÌNH THẮNG

LẬP TRÌNH SONG SONG TRÊN
NỀN ĐƠN VỊ XỬ LÝ ĐỒ HỌA VÀ
ỨNG DỤNG

Ngành: Công nghệ Thông tin
Chuyên ngành: Hệ thống Thông tin
Mã số: 60 48 05

LUẬN VĂN THẠC SĨ
NGƯỜI HƯỚNG DẪN KHOA HỌC: TS. Nguyễn Trí Thành


Hà Nội – 2010

2

MỤC LỤC
LỜI CAM ĐOAN................................................................................................. 1
MỤC LỤC.............................................................................................................2
DANH MỤC HÌNH VẼ........................................................................................4
KÝ TỰ VIẾT TẮT................................................................................................5
LỜI CẢM ƠN.......................................................................................................6
MỞ ĐẦU...............................................................................................................7
CHƢƠNG 1: GIỚI THIỆU..................................................................................9
1.1. Mục đích của lập trình song song...............................................................9
1.2. Mục tiêu của luận văn...............................................................................12
1.3. Tổ chức của luận văn................................................................................12
CHƢƠNG 2: TỔNG QUAN VỀ ĐƠN VỊ XỬ LÝ ĐỒ HỌA (GRAPHIC
PROCESSING UNIT-GPU)............................................................................... 14
2.1. Tóm tắt lịch sử phát triển của đơn vị xử lý đồ họa (GPU)........................14
2.2. Sự khác nhau giữa GPU và CPU..............................................................15
2.3. Mô hình xử lý song song dữ liệu.............................................................. 17
2.4. Lợi ích sự thực thi tính toán song song.....................................................21
2.5. Phân cấp bộ nhớ........................................................................................22
2.5.1. Bộ nhớ toàn cục (global memory) và bộ nhớ cục bộ (local memory) 23

2.5.2. Bộ nhớ chia sẻ (shared memory)........................................................24
2.5.3. Bộ nhớ texture và constant................................................................. 24
2.6. Các chiến lƣợc tối ƣu hóa trên GPU........................................................24
2.6.1. Tối đa hóa thực thi song song.............................................................25
2.6.2. Tối ƣu hóa sử dụng bộ nhớ................................................................ 25

2.6.3. Tối ƣu hóa thực thi các thread............................................................26
2.6.4. Tối ƣu hóa sử dụng chỉ lệnh...............................................................27
2.7. nVidia CUDA............................................................................................27
2.8. Thrust........................................................................................................ 28

3

CHƢƠNG 3: MÔ HÌNH TRƢỜNG NGẪU NHIÊN CÓ ĐIỀU KIỆN
(CONDITIONAL RANDOM FIELDS -CRFS) .................................................

3.1.Mô hình lý thuyết CRFs .....................................

3.2.Ƣớc lƣợng tham số mô hình CRFs ....................

3.3.Ứng dụng CRFs trong trích chọn thông tin ........
CHƢƠNG 4: ỨNG DỤNG GPU SONG SONG TỪNG PHẦN CÔNG CỤ
CRF++.................................................................................................................
4.2. Công cụ CRF++ ........................................................................................
4.2.1. Training ...............................................................................................
4.2.2. Testing .................................................................................................

4.3.Song song CRF++ ..............................................
4.3.1. Song song phần Training ....................................................................

4.4.Kết quả thực nghiệm ..........................................
4.4.1. Môi trƣờng thực nghiệm .....................................................................
4.4.2. Đánh giá kết quả .................................................................................
KẾT LUẬN .........................................................................................................
TÀI LIỆU THAM KHẢO...................................................................................

4

DANH MỤC HÌNH VẼ

Hình 1: Sự khác nhau giữa CPU và GPU – GPU có nhiều bộ xử lý để định
hướng xử lý song song dữ liệu [2]. .....................................................................
Hình 2: So sánh tốc độ tính toán giữa CPU và GPU [2] ..................................
Hình 3: Nguyên lý lập trình trên GPU [2] .........................................................
Hình 4: Ví dụ về lưới 5 chiều của thread ...........................................................
Hình 5: Luật Amdahl's – tăng tốc phụ thuộc vào phần mã song song và số
lượng thread [3] ..................................................................................................
Hình 6: Thu thập và phân tán các hoạt động bộ nhớ [3] ..................................
Hình 7: Các loại bộ nhớ trong GPU [2] ............................................................
Hình 8: Phân cấp bộ nhớ theo khía cạnh phần mềm (trái) và phần cứng (phải)
[2] ........................................................................................................................
Hình
9: Phân rã tại nhánh phụ thuộc dữ liệu ...........
Hình 10: Điện toán GPU được tăng cường bởi kiến trúc CUDA .....................
Hình 11: So sánh mô hình HMMs, MEMMs và CRFs .......................................
Hình
12: Ví dụ tệp tin huấn luyện .............................
Hình
13: Tệp tin mẫu (template) ...............................
Hình
14: Kết quả thực hiện crf_learn .......................
Hình
15: Kết quả thực hiện crf_test ..........................
Hình 16: So sánh thời gian thực hiên tính toán trên GPU-CPU .......................

Hình 17: Biểu đồ thời gian thực hiên tính toán trên GPU-CPU .......................
Hình 18: Biểu đồ hình cột so sánh thời gian thực hiên tính toán trên GPU-CPU
.............................................................................................................................
Hình
19: Tập dữ liệu CoNLL 2000-shared task ........
Hình
20: So sánh thời gian thực hiện phần training

5

2D
3D
ALU
API
CPU
CRFs
CUBLAS
CUDA
CUDPP
CUFFT
DRAM
GPGPU
GPU
LBFGS
MIRA
MPI
OpenCL
OpenMP
PVM

SIMD
SIMT
VLSI

6

LỜI CẢM ƠN
Để hoàn thành luận văn này tác giả đã nhận đƣợc sự giúp đỡ từ rất nhiều
cơ quan, đoàn thể và cá nhân.
Trƣớc hết tôi xin chân thành cảm ơn các thầy giáo, cô giáo trong Khoa
Công nghệ Thông tin, trƣờng Đại học Công nghệ, Đại học Quốc gia Hà Nội đã
tận tình giảng dạy, trang bị cho tôi những kiến thức quý báu trong suốt quá trình
học tập tại trƣờng.
Tôi xin bày tỏ lòng biết ơn sâu sắc đến TS. Nguyễn Trí Thành - ngƣời thầy
đã trực tiếp hƣớng dẫn tôi trong suốt quá trình xây dựng và hoàn thành luận văn
này.
Đồng thời, xin chân thành cảm ơn lãnh đạo Viện Công nghệ Thông tin
thuộc Viện Khoa học và Công nghệ Quân sự đã tạo điều kiện để tôi thực hiện
thành công luận văn tốt nghiệp này.
Hà Nội, tháng 10 năm 2010
Học viên

Hoàng Đình Thắng

7

MỞ ĐẦU
Tính toán song song hay xử lý song song là quá trình xử lý thông tin trong

đó nhấn mạnh việc nhiều đơn vị dữ liệu đƣợc xử lý đồng thời bởi một hay nhiều
bộ xử lý để giải quyết một bài toán. Trái ngƣợc với xử lý nối tiếp, đòi hỏi phải
xử lý các công việc theo thứ tự tuần tự
Có hai kiểu song song đó là:

Song song về dữ liệu (data parallelism): là cơ chế sử dụng nhiều
đơn vị xử lý thực hiện cùng một thao tác trên nhiều đơn vị dữ liệu .

Song song lệnh (control parallelism): là cơ chế trong đó nhiều
thao tác khác nhau tác động lên nhiều đơn vị dữ liệu khác nhau một
cách đồng thời.
Chíp đồ họa, với hàng chục lõi đƣợc sử dụng để tạo ra hình ảnh thực trên
màn hình máy tính, rất phù hợp cho các nhiệm vụ xử lý song song. Trong khi đó
thì bộ xử lý, với những lõi mạnh hơn nhƣng số lƣợng ít hơn (giống nhƣ Core
i7) lại phù hợp hơn cho các ứng dụng xử lý nối tiếp.
Trong một báo cáo các nhà nghiên cứu của Intel cho biết, trung bình,
NVIDIA GeForce GTX 280 (tung ra hồi tháng 6/2008) nhanh hơn gấp 2,5 lần so
với bộ xử lý (BXL) Intel Core i7 960 3,2GHz, và nhanh hơn trên 14 lần trong
những hoàn cảnh nhất định.
Xử lý song song là hƣớng nghiên cứu quan trọng, nó giúp cho việc thực
hiện các bài toán đƣợc nhanh hơn rất nhiều so với xử lý tuần tự. Luận văn sẽ
hƣớng tới tìm hiểu bài toán xử lý song song trên nền đơn vị xử lý đồ họa
(Graphic Processing Unit-GPU), một trong những hƣớng xử lý song song đang
đƣợc phát triển mạnh trong thời gian gần đây.
Đồng thời luận văn này cũng tìm hiểu về mô hình trƣờng ngẫu nhiên có
điều kiện (Conditional Random Fields-CRFs), một mô hình đƣợc ứng dụng

thành công trong rất nhiều lĩnh vực nhƣ tin-sinh học, xử lý ngôn ngữ tự nhiên và
khai phá text/web.
CRF++ là một công cụ đƣợc xây dựng cho mô hình CRF, áp dụng cho các
tác vụ xử lý ngôn ngữ tự nhiên nhƣ: nhận dạng thực thể tên (Named Entity
Recognition), trích chọn thông tin (Information Extraction) và Text Chunking.
CRF++ là một phần mềm nguồn mở, đƣợc xây dựng bằng ngôn ngữ C++.

8

Luận văn này sẽ nghiên cứu cách mà tác giả của CRF++ thực hiện mô hình
CRF lý thuyết. Từ đó đề xuất cách song song một số phần của CRF++ sử dụng
mô hình song song trên đơn vị xử lý đồ họa.

9

CHƢƠNG 1: GIỚI THIỆU
1.1. Mục đích của lập trình song song
Yêu cầu thực tế cần thực hiện khối lƣợng tính toán lớn: bài toán xử lý ngôn
ngữ tự nhiên, bài toán xử lý ảnh 3D, thăm dò dầu khí, dự báo thời tiết,...(máy
tính xử lý tuần tự kiểu von Neumann là không đáp ứng yêu cầu)
Xử lý song song là quá trình xử lý gồm nhiều tiến trình đƣợc kích hoạt
đồng thời và cùng tham gia giải quyết một bài toán, nói chung xử lý song song
đƣợc thực hiện trên những hệ thống đa bộ xử lý.
Phân biệt xử lý song song với tuần tự:

Trong xử lý tuần tự với một bộ xử lý thì tại mỗi thời điểm chỉ

thực hiện đƣợc một phép toán.

Trong xử lý song song thì nhiều bộ xử lý cùng kết hợp với nhau
để giải quyết cùng một bài toán cho nên giảm đƣợc thời gian xử lý vì
mỗi thời điểm có thể thực hiện đồng thời nhiều phép toán.
Mục đích của xử lý song song: là thực hiện tính toán nhanh trên cơ sở sử
dụng nhiều bộ xử lý đồng thời. Cùng với tốc độ xử lý nhanh hơn, việc xử lý
song song cũng sẽ giải đƣợc những bài toán phức tạp yêu cầu khối lƣợng tính
toán lớn.
Ba yếu tố chính dẫn đến việc xây dựng các hệ thống xử lý song song:

Tốc độ xử lý của các bộ xử lý theo kiểu von Neumann đã dần
tiến tới giới hạn, không thể cải tiến thêm đƣợc do vậy dẫn tới đòi hỏi
phải thực hiện xử lý song song.

Hiện nay giá thành của phần cứng (CPU) giảm mạnh, tạo điều
kiện để xây dựng những hệ thống có nhiều bộ xử lý với giá thành hợp
lý.

Sự phát triển của công nghệ mạch tích hợp (VLSI) cho phép tạo
ra những hệ thống có hàng triệu bóng bán dẫn (transistor) trên một
chíp.

Vấn đề xử lý song song liên quan trực tiếp đến: kiến trúc máy tính, phần
mềm hệ thống (hệ điều hành), thuật toán và ngôn ngữ lập trình,v.v….

Hệ thống tính song song: là một tập các bộ xử lý (thƣờng là cùng một loại)
kết nối với nhau theo một kiến trúc nào đó để có thể hợp tác với nhau trong hoạt
động và trao đổi dữ liệu đƣợc với nhau.

10

Chúng ta dễ nhận thấy là độ phức tạp của xử lý song song sẽ lớn hơn xử lý
tuần tự rất nhiều, và tập trung chủ yếu ở phƣơng diện trao đổi dữ liệu và đồng
bộ các tiến trình.
Để cài đặt các thuật toán song song trên các máy tính song song chúng ta
phải sử dụng những ngôn ngữ lập trình song song. Nhiều ngôn ngữ lập trình
song song đang đƣợc sử dụng nhƣ: Fortran 90, Pthread [24] với Fortran/C++,
MPI [21] với C/C++, PVM [22] với C/C++, OpenMP [23] với C/C++, v.v….
Một số khó khăn của lập trình song song truyền thống:

Khó khăn thứ nhất – Suy nghĩ tuần tự

Chúng ta có thể thấy rằng tƣ duy tuần tự là do môi trƣờng lập trình quyết
định. Từ thập niên 80 đến khoảng gần đây, chúng ta chủ yếu làm việc với máy
tính cá nhân, và mô hình thực thi trên đó là từng bƣớc một. Cũng có máy tính
song song, nhƣng hiếm ngƣời đƣợc dùng nó trong công việc hàng ngày, vì
chuyện xây dựng một hệ máy tính nhƣ vậy ở mức quốc gia đã cực kỳ tốn kém
chứ đừng nói là công ty hay cá nhân.
Cũng chính vì thói quen suy nghĩ tuần tự đã ăn sâu nhƣ vậy nên giờ chuyển

sang suy nghĩ kiểu song song rất là mệt mỏi, vì sẽ phải chú ý tới các lỗi đặc thù của
nó, nhƣ bế tắc (deadlock), khóa sống (livelock), điều kiện cạnh tranh,v.v….

Khó khăn thứ hai – Mở rộng hiệu năng

Qui tắc Amdahl [3] trong lập trình song song cho chúng ta biết là lượng
tăng tốc tối đa có thể đạt được bằng việc song song hóa thuật toán thì tỷ lệ
nghịch với phần mã chương trình không thể chuyển sang dạng song song. Tức là
cho dù chỉ còn 10% mã chƣơng trình không thể song song hóa, thì sự tăng tốc
chƣơng trình đó cũng không vƣợt quá 10 lần. Tuy nhiên để ƣớc lƣợng mức độ
cải tiến theo kiểu này rất khó, vì không thể xác định chính xác bao nhiêu phần
trăm mã chƣơng trình thật sự chạy song song, do trong lúc thực thi song song,
mọi thứ lại rất có thể bị chuyển ngược lại thành tuần tự, nhƣ khi có tranh chấp
tài nguyên dùng chung, hay có truy cập đến nhiều vị trí khá cách xa nhau trong
bộ nhớ. Đây chính là một trong những hạn chế chính của mô hình lập trình song
truyền thống (vốn thƣờng cài đặt cách điều khiển tiểu trình qua cơ chế khóa, hay
qua giao diện truyền thông điệp, hay nhiều cách khác nữa đòi hỏi sự đồngbộ hóa
– tức là là tiến trình này đợi tiến trình kia hoàn tất công việc rồi mới làm tiếp
phần việc tiếp theo của mình) khi áp dụng cho nhiều nhân/lõi. Nói một cách dễ
hiểu, nếu chúng ta chỉ phải đợi từng người một hoàn tất công việc của họ một
cách độc lập, thì thời gian chờ đợi có thể coi là tăng tuyến tính với số người cần

11

đợi/đồng bộ. Nhưng nếu chúng ta phải đợi cùng lúc nhiều người, và kết quả
công việc của họ lại phụ thuộc lẫn nhau, thì thời gian chờ đợi sẽ tăng tổ hợp và
rất khó xác định, chứ không đơn giản chỉ là tăng tuyến tính.

Còn có một khó khăn cơ bản hơn nữa trong mở rộng hiệu năng với số
nhân/lõi. Mô hình lập trình song song truyền thống tiếp cận bài toán cần giải
quyết theo kiểu top-down, bằng cách chia một bài toán lớn thành nhiều tác vụ
con, và mỗi tác vụ này sẽ đƣợc giao cho một bộ xử lý/nhân/lõi. Vấn đề rắc rối ở
đây là khi số lƣợng bộ xử lý/nhân/lõi tăng lên đến hàng chục, hay hàng trăm
nhƣ hiện nay, thì số tác vụ con đã đƣợc thiết kế để giao nhằm tận dụng sức
mạnh tính toán của chúng lại không có đủ. Cách tiếp cận phổ biến nhất cho tình
huống này là lại cố chia nhỏ các tác vụ con đó thành nhiều đơn vị thực thi nhỏ
hơn. Nhƣ vậy, cách làm này bị phụ thuộc vào từng thế hệ phần cứng bộ xử lý,
dẫn đến chuyện không thể mở rộng việc thực thi chƣơng trình một cách dễ dàng
theo kiểu không cần phải thay đổi, sửa chữa gì về mặt thuật toán hay mã nguồn
cài đặt. Và suy cho cùng thì nếu một bài toán mà đƣợc chia thành vài chục tác
vụ con chạy song song sẽ vô cùng khó quản lý và gỡ rối.

Khó khăn thứ ba – Tuần tự sang song song

Việc cố gắng chuyển mã từ tuần tự sang song song dựa trên tác vụ là quá
trình này cần rất nhiều thời gian, có khi cả vài năm trời. Do tốc độ gia tăng số
nhân/lõi hiện tại quá nhanh, nên nhiều khi thuật toán song song mà chúng ta đã
bỏ ra vài năm kể từ năm nay để thiết kế lại không mở rộng tốt với số nhân/lõi
của vài năm nữa, ở thời điểm chúng ta hoàn tất việc cài đặt nó một cách song
song.
Ý
tƣởng gán một công việc nhỏ cho từng bộ xử lý/nhân/lõi trong máy tính
nhằm tăng hiệu năng phần mềm chạy trên đó là hoàn toàn tự nhiên và đƣợc đúc
kết từ kinh nghiệm trong đời sống hàng ngày. Tuy nhiên để tận dụng đƣợc hết
sức mạnh của hàng trăm, rồi hàng ngàn nhân/lõi trong tƣơng lai, chúng ta có lẻ
cần phải “đi trƣớc đón đầu” bằng cách tạo ra hàng chục ngàn, hàng trăm ngàn
công việc nhỏ li ti cung cấp cho đội quân nhân/lõi đông đảo và ngày một gia

tăng đó.
Với những khó khăn đó, yêu cầu về một mô hình lập trình song kiểu mới
linh hoạt hơn và theo sát với sự thay đổi về số lƣợng nhân /lõi của một hệ thống
máy tính. Đó là lập trình song song đa dụng trên đơn vị xử lý đồ họa-GPU.

12

1.2. Mục tiêu của luận văn
Vì giới hạn của phần cứng, xu hƣớng tăng số lõi (cores) thay vì tăng xung
nhịp (clock rate) đang trở nên phổ biến. CPU thì có multicores, còn GPU thì có
many-cores. Ngày nay, GPU có thể hoạt động nhanh hơn cả CPU trong việc xử
lý tính toán. Cụ thể nhờ số lƣợng cores lớn (vài trăm so với 2,4, hoặc 8 của
CPU), tốc độ truy xuất bộ nhớ nhanh (85GB/s với G80, 150GB/s với GTX200).
Nhờ thế, vai trò của GPU đã vƣợt ra ngoài phạm vi truyền thống, đó là chạy các
ứng dụng tính toán. Tuy nhiên, GPU vẫn chƣa thay thế hoàn toàn đƣợc CPU, do
có nhiều tác vụ thực hiện hiệu quả hơn trên CPU. Do đó, GPU chỉ đóng vai trò
là một co-processor.
Mục đích của luận văn này là giới công nghệ song song đƣợc dùng trên
nền đơn vị xử lý đồ họa (GPU) và cung cấp cái nhìn tổng quan về xu hƣớng
hiện nay trong tính toán song song đa dụng trong GPU. Trình bày về các lợi thế
của tính toán song song quy mô lớn trên GPU.
Mô hình trƣờng ngẫu nhiên có điều kiện (Conditional Random FieldsCRFs), một mô hình đƣợc ứng dụng thành công trong rất nhiều lĩnh vực nhƣ
tin-sinh học, xử lý ngôn ngữ tự nhiên và khai phá text
CRF++ là một công cụ xây dựng cho mô hình CRF, đƣợc viết bằng ngôn
ngữ C++. Luận văn này sẽ ứng dụng GPU để song song hóa từng phần của
CRF++, nhằm mục đích cải thiện tốc độ tính toán của CRF++, nhất là trong
trƣờng hợp xử lý số liệu lớn (hàng chục nghìn câu, hàng triệu thuộc tính).

1.3. Tổ chức của luận văn

Luận văn này gồm 4 chƣơng, với nội dung sơ bộ nhƣ sau:
Chương 1 - Giới thiệu nêu lên mục đích của lập trình song song, những khó
khăn của lập trình song song truyền thống, dẫn đến yêu cầu một mô hình lập
trình song song kiểu mới linh hoạt hơn. Chƣơng này cũng trình bày mục tiêu
của luận văn, tổ chức của luận văn.
Chương 2 - Tổng quan về đơn vị xử lý đồ họa (GPU), cung cấp cái nhìn
tổng quan về tính toán song song đa dụng trên đơn vị xử lý đồ họa. Mô tả sự
khác nhau cơ bản giữa đơn vị xử lý trung tâm (CPU) và đơn vị xử lý đồ họa
(GPU). Phần lớn của chƣơng này dành cho việc giải thích các nguyên tắc cơ bản
của tính toán song song đa dụng trên đơn vị xử lý đồ họa và giao diện lập trình
ứng dụng (API) trên GPU.

13

Chương 3 - Mô hình trường ngẫu nhiên có điều kiện (CRF), trình bày mô
hình lý thuyết CRF, phƣơng pháp ƣớc lƣợng tham số của mô hình CRF và một
số ứng dụng của CRF.
Chương 4 - Ứng dụng GPU song song hóa từng phần công cụ CRF++,
giới thiệu công cụ CRF++, cách thức mà tác giả của CRF++ thực hiện, từ đó đề
xuất chiến lƣợc song song CRF++ bằng GPU thông qua các thƣ viện lập trình
cho GPU nhƣ CUDA, Thrust. Phần cuối của chƣơng sẽ đƣa ra kết quả thực
nghiệm cũng nhƣ một số đánh giá, nhận xét.

14

CHƢƠNG 2: TỔNG QUAN VỀ ĐƠN VỊ XỬ LÝ
ĐỒ HỌA (GRAPHIC PROCESSING UNIT-GPU)
2.1. Tóm tắt lịch sử phát triển của đơn vị xử lý đồ họa (GPU)

Trong suốt 20 năm qua GPUs đã trải qua những phát triển lớn. Bắt đầu phát
triển từ đơn vị xử lý đồ họa 2D đơn giản, đến đa mục đích, có thể lập trình
đƣợc, song song mức độ cao, có nhiều lõi đơn vị xử lý với khả năng tính toán
phi thƣờng và băng thông bộ nhớ rất cao.
Lịch sử của GPUs những năm 1970 với các máy tính có Atari 8-bit. Những
chíp đồ họa này đƣợc sử dụng để hòa trộn đồ họa và dữ liệu văn bản rồi hiển thị
chúng lên màn hình. Những năm 1980, kiến trúc của chíp này trở thành nền tảng
của sản xuất chíp hàng loạt tiếp theo, đƣợc tích hợp trong Commodore Amiga.
Chíp này là chip đầu tiên có đầy đủ các đặc tính tăng tốc đồ họa – nó chứa các
đặc tính nhƣ: vẽ hình ảnh gốc, tô màu hình ảnh, chuyển khối hình ảnh,
v.v….Đặc tính cách mạng là tất cả video đƣợc đẩy vào phần cứng. Năm 1984,
gần 10 năm sau khi phần cứng tăng tốc đồ họa trở thành chuẩn, IBM giới thiệu
tăng tốc 2D/3D đầu tiên dƣới cái tên IBM Professional Graphics Controller,
nhƣng thành công thì không đƣợc nhƣ mong đợi. Việc thiếu tính tƣơng thích,
xử lý chậm và giá cao ($4.500) làm cho dự án này thất bại [7].
Trong suốt những năm 1990, nhu cầu tăng tốc đồ họa trở nên cấp thiết, bởi
vì số lƣợng máy trạm ngày càng tăng với nền tảng công nghệ của Microsoft
Windows. Năm 1993, S3 Graphics giới thiệu chíp đơn 2D tăng tốc đầu tiên - S3
86C911, dƣới tên mã là Porsche 911. Chíp này thiết lập chuẩn tăng tốc 2D trong
vòng vài năm. Năm 1995 gần nhƣ tất cả các nhà sản xuất chíp đã bổ sung hỗ trợ
tăng tốc 2D vào sản phẩm của họ.
Giữa những năm 1990 đồ họa 3D thời gian thực trở nên phổ biến hơn trong
máy tính và trò chơi điều khiển. Nhu cầu đồ họa 3D thời gian thực dẫn đến phát
triển tăng tốc 3D thời gian thực đầu tiên. Các chíp giá rẻ nhƣ S3 ViRGE, Matrox
Mystique hay Ati Rage đƣợc dựa trên 2D tăng tốc và thêm các đặc tính 3D.
Bƣớc đột phá đầu tiên đến năm 1996, khi 3Dfx Interactive giới thiệu tăng tốc
3D đầu tiên đầu đủ tính năng có tên là Voodoo [8]. Gia tăng tốc độ này xác định
tiêu chuẩn mới cho chip đồ họa 3D cho ba năm tiếp theo. Bƣớc đột phá lớn thứ
hai đến năm 1999 khi tổng công ty nVidia giới thiệu GPU đầu tiên – NV10,

15

dƣới tên mã GeForce 256. Tất cả các con chíp hiện nay về cơ bản đều xuất phát
từ kiến trúc này.
Vào cuối năm 2006 nVidia giới thiệu kiến trúc thiết bị hợp nhất cho tính
toán đầu tiên - Compute Unified Device Architecture (CUDA). Các công ty đối
thủ AMD/ATI giới thiệu kiến trúc của họ (ATI FireStream) vài tháng sau đó.
Thời điểm này GPU trở nên dễ tiếp cận để phát triển phần mềm bằng các ngôn
ngữ lập trình chuẩn công nghiệp và thiết lập cách thức mới cho tính toán hiệu
năng cao [2].

2.2. Sự khác nhau giữa GPU và CPU
Ý
tƣởng chính của tính toán song song đa dụng trên GPU (GPGPU) là sử
dụng nhiều bóng bán dẫn (transistor) để xử lý dữ liệu và xử lý dữ liệu song song.
Đây là sự khác biệt chính giữa CPU và GPU. GPU chủ yếu định hƣớng các thao
tác song song dữ liệu hơn là trữ dữ liệu (caching data) và điều khiển luồng [2].
Nhu cầu này chủ yếu xuất phát từ dựng hình đồ họa, bởi vì thiết bị đồ họa bắt
buộc phải xử lý một lƣợng lớn các phần tử dữ liệu đồ họa (nhƣ các điểm ảnh,
đỉnh và mảnh) và thao tác trên các phân tử này (lightning, blending, clipping,
texturing, …). Song song là cách để giảm lƣợng thời gian cần thiết để xử lý dữ
liệu và giảm chi phí tổng thể bằng cách phân phối nó trong xử lý các phần tử.
Nguyên tắc cơ bản là quá trình dựng hình đồ họa là cố định. Dữ liệu đƣợc xử lý
bởi phần cứng đồ họa đi qua nhiều giai đoạn trƣớc khi chúng đƣợc hiển thị và
chuỗi sự kiện này là không thay đổi.

Hình 1: Sự khác nhau giữa CPU và GPU – GPU có nhiều bộ xử lý để định
hướng xử lý song song dữ liệu [2].

16

Hình 2: So sánh tốc độ tính toán giữa CPU và GPU [2]
CPU phải xử lý nhiều tác vụ khác nhau vào cùng một thời gian. Vì vậy
CPU phải đƣợc tối ƣu hóa cho mục đích này, chủ yếu lƣu trữ dữ liệu quan trọng
đƣợc dùng bởi tiến trình đang chạy và nhanh chóng chuyển ngữ cảnh giữa các
tiến trình đang chạy. Tất cả các tác vụ đƣợc cung cấp một thời gian xử lý xác
định trƣớc để thực thi mã của chúng. Khi đến thời gian này, hệ điều hành
chuyển CPU sang tiến trình tiếp theo. Chuyển đổi ngữ cảnh giữa các tiến trình
đang chạy có thể đƣợc tính toán với cƣờng độ lớn.

17

Ngƣợc lại, GPU xử lý nhiều nhất một nhiệm vụ tại một thời điểm nhƣng
thực hiện nhiều lần song song. GPU sử dụng mô hình song song dữ liệu, để có
thể giải quyết các vấn đề số học cƣờng độ cao hơn CPU. Khi cùng một đoạn mã
GPU đƣợc thực hiện song song nhiều lần thì không cần kiểm soát luồng và quản
lý bộ nhớ đệm (cache). Thực thi tác vụ song song không đƣợc hỗ trợ trong
GPU. Có nghĩa là, không thể thực thi hai hoặc nhiều chƣơng trình khác nhau
trên cùng GPU vào cùng một thời điểm.
Mô hình xử lý dữ liệu song song ánh xạ các phần tử dữ liệu vào các đơn vị
làm việc cơ sở đƣợc gọi là các luồng (thread). Tính song song thread cùng với
phân cấp bộ nhớ chia sẻ và hàng rào đồng bộ hóa giữa các luồng làm nên khái
niệm trừu tƣợng về mô hình lập trình song song đa dụng của GPU [2].

2.3. Mô hình xử lý song song dữ liệu
Mục này sẽ trình bày các khái niệm cơ bản trong đơn vị xử lý đồ họa.
Kernel là một đoạn mã chƣơng trình, đƣợc thể hiện bởi một hàm hay thủ

tục viết bằng một ngôn ngữ lập trình cụ thể. Thread là một thực thể chạy mã nhị
phân, đƣợc thực thi song song nhiều lần [2]. Có thể nói kernel là một “mẫu
hàm” cho một nhóm thread. Hai thuật ngữ quan trọng tiếp theo là host và device.
Host là bao gồm bộ xử lý trung tâm và DRAM của CPU, còn device gồm các bộ
xử lý và DRAM của GPU. Host và device đƣợc phân tách bởi không gian địa
chỉ của hai DRAM. Host thực thi chƣơng trình chính (mã tuần tự) còn device
thực thi kernel (mã song song). Device trong mô hình này làm việc giống nhƣ
một bộ đồng xử lý (co-processor) đối với host. Hình 3 thể hiện cách thức thực
thi mã tuần tự và song song.
GPU thread dùng xử lý dữ liệu song song và mô hình lập trình. Trong mô
hình này, các phần tử dữ liệu cơ sở đƣợc lƣu trong bộ nhớ GPU đƣợc ánh xạ
vào thread đang chạy. Bộ nhớ GPU (không gian địa chỉ) là một mảng tuyến tính
của các phần tử cơ bản (bytes). Để ánh xạ thread vào bộ nhớ đối tƣợng chúng ta
cần biết cách tổ chức thread. Cơ cấu tổ chức này phải có khả năng xác định rõ
đối tƣợng bộ nhớ từ các giá trị định danh thread đƣợc sinh ra một cách tự động.
Để làm đƣợc điều này, cách dễ dàng nhất là tổ chức thread thành lƣới (grid) ảo
đa chiều của các thread. Với công nghệ CUDA, lƣới này có 5 chiều và để định
hƣớng tốt hơn, lại đƣợc chia thành 2 loại: khối 3 chiều của thread và lƣới 2
chiều của khối của thread.

18

Hình 3: Nguyên lý lập trình trên GPU [2]
Số định danh duy nhất của thread có thể ƣớc lƣợng từ một số biến liên
quan, đƣợc khởi tạo khi lƣới của khối thread đƣợc liệt kê. Các biến này có thể
truy cập từ bên trong mỗi kernel. Mỗi thread có biến riêng của nó, chứa tọa độ

19

ba chiều
trục , ,

x,

y,

z trong

khối. Khối thread chứa các biến chiều

và tọa độ 2 chiều

x,

y trong

x,

y,

z ứng

lƣới khối thread. Các chiều của

thread cũng có thể truy cập từ trong các biến

x,

y.

với các

lƣới khối

Các chiều của

khối thread và của lƣới phải đƣợc thiết lập trƣớc khi chạy các tính toán. Số
định danh duy nhất của thread trong khối thread và số định danh duy nhất của
block trong grid đƣợc tính nhƣ sau [2]:

threadId =

blockId =

Hình 4: Ví dụ về lưới 5 chiều của thread
Cơ cấu phân cấp cung cấp phƣơng tiện để tính toán trên các cấu trúc dữ
liệu nhƣ véctơ, ma trận hay mảng ba chiều. Tuy nhiên do hạn chế của phần
cứng, kích thƣớc của khối thread hay số thread trong mỗi block là giới hạn1.
1

Đối với nVidia CUDA tương thích với 1.x, kích thước lớn nhất của khối thread là 512x512x64,
nhưng có nhiều nhất 512 thread trong mỗi block.

20

Nghĩa là chúng ta không thể gọi khối thread với kích thƣớc bất kỳ. Đây là một hạn
chế, nhƣng chúng ta có thể “lợi dụng” tính toán theo một số khối của các thread.

Nếu làm điều này, chúng ta luôn phải xác định kích thƣớc của grid để thực hiện các
tính toán. Tối đa kích thước của khối thread luôn luôn có nghĩa là giảm thiểu kích
thước của grid và ngược lại. Vậy làm thế nào để chúng ta chọn kích thƣớc của
khối thread, mà vẫn tuân theo giới hạn của phần cứng. Ví dụ, nếu chúng ta muốn
ánh xạ véctơ kích thƣớc

xác định kích thƣớc

với khối kích thƣớc

của grid của khối thread. Có thể tính toán nhƣ sau:
ϵ

and 1 ≤
1≤

≤ maxBlockDimensionX

≤ maxThreadsPerBlock

Để xác định kích thƣớc của
kích thƣớc

*

, chúng ta cần

vào block kích thƣớc

ϵ

trong trƣờng hợp ánh xạ ma trận
,

:

and 1 ≤

≤ maxBlockDimensionX

ϵ N and 1 ≤

≤ maxBlockDimensionY

1≤

*

≤ maxThreadsPerBlock

Trƣờng hợp ánh xạ mảng 3 chiều * *
trên, với thay đổi điều kiện ban đầu.

1≤

chúng ta dùng biểu thức nhƣ

and 1 ≤

≤ maxBlockDimensionX

and 1 ≤

≤ maxBlockDimensionY

and 1 ≤

≤ maxBlockDimensionZ

*

≤ maxThreadsPerBlock

*

21

2.4. Lợi ích sự thực thi tính toán song song
Để đạt đƣợc lợi ích tối đa từ tính toán song song chúng ta cần tìm giải pháp
làm thế nào để song song mã tuần tự. Trong GPGPU điều này đƣợc thực hiện
bởi song song thread và mô hình thực thi song song dữ liệu. Lợi ích tối đa (tăng
tốc lý thuyết) có thể đƣợc diễn tả bởi luật Amdahl's [3]

Trong đố

là một phần của chƣơng trình có thể đƣợc thực hiện song song,

tƣợng trƣng cho phần mã đƣợc thực hiện tuần tự và là số bộ xử lý hoặc

thread thực hiện phần song song. Hình 5 minh họa tăng tốc lý thuyết cho các
phần khác nhau của mã song song phụ thuộc vào số lƣợng thread thực hiện song
song.

Hình 5: Luật Amdahl's – tăng tốc phụ thuộc vào phần mã song song và số lượng
thread [3]

22

2.5. Phân cấp bộ nhớ
Ngày này, GPUs hỗ trợ đánh địa chỉ bộ nhớ byte-wise và hỗ trợ thu thập
(gather) và phân tán (scatter) các hoạt động bộ nhớ. Truy cập bộ nhớ song song
là giải pháp chính cho thông lƣợng bộ nhớ lớn và xử lý dữ liệu song song. Điều
quan trọng cần đề cập đến là tất cả các hoạt động bộ nhớ phải đƣợc hợp nhất.
Hợp nhất truy cập bộ nhớ nghĩa là đọc từ một tập địa chỉ liên tục phải tƣơng ứng
với tổ chức thread (số định danh thread). Cách tốt nhất để hợp nhất bộ nhớ truy
cập là ánh xạ thread và block vào bộ nhớ đối tƣợng. Không hợp nhất hoặc truy
cập bộ nhớ ngẫu nhiên dẫn đến đọc và ghi tuần tự dữ liệu và làm mất hiệu suất
[2].

Hình 6: Thu thập và phân tán các hoạt động bộ nhớ [3]
Có thể xem xét bộ nhớ GPU từ hai khía cạnh: phần cứng và phần mềm. Với
khía cạnh phần mềm, cần phân biệt giữa các bộ nhớ global, local, shared, texture
và constant. Mỗi loại bộ nhớ có chức năng đặc thù và mục đích sử dụng riêng.
Với cái nhìn phần cứng, chỉ cần phân biệt giữa bộ nhớ thiết bị (DRAM), bộ nhớ
chia sẻ (shared memory) với constant và texture cache.

23

Hình 7: Các loại bộ nhớ trong GPU [2]

Hình 8: Phân cấp bộ nhớ theo khía cạnh phần mềm (trái)
và phần cứng (phải) [2]
2.5.1. Bộ nhớ toàn cục (global memory) và bộ nhớ cục bộ (local memory)
Bộ nhớ toàn cục là phần bộ nhớ lớn nhất trong thiết bị GPU. Bộ nhớ này nằm
trong DRAM của thiết bị và có thể truy cập từ tất cả các thread trong grid và từ
host-device thông qua thƣ viện runtime đặc thù. Các đối tƣợng bộ nhớ khai báo
trong không gian bộ nhớ toàn cục có thời gian tồn tại là thời gian của ứng dụng. Bộ
nhớ toàn cục có thông lƣợng bộ nhớ rất lớn (hàng trăm gigabyte/giây). Hạn chế
chính của loại bộ nhớ này là độ trễ rất lớn khi đọc và ghi dữ liệu (hàng