2. Hướng tiếp cậ n giải thuật
1.3. Thao tác nguyên tử (atomic operation)
Chúng ta dễ dàng nhận ra rằng, khi tính theo cách như trên bằng nhiều luồng của GPU
thì sẽ xảy ra đụng độ. Điều đó diễn ra khi hai hay nhiều node cùng trỏ tới một node
(hay nói cách khác một node nằm ở danh sách liên kết ra của nhiều node), khi đó hai
luồng có thể đồng thời truy cập vào cùng một node ra để cộng dồn giá trị PageRank.
Nhiều trang web có thể được trỏ tới bởi rất nhiều trang web khác như các trang chủ
thường được các trang con trong site trỏ tới, và những trang này thường là những trang
có PageRank cao (vì có nhiều liên kết tới). Để xử lý vấn đề này cần có một cơ chế khoá
hiệu quả để tuần tự hoá việc truy cập vào các node.
Trong các thế hệ GPU có khả năng tính toán từ 1.1 trở lên, CUDA cung cấp một cơ chế
gọi là các hàm nguyên tử - atomic function. Các hàm này thực hiện các thao tác đọc-
đơn nhất hiểu theo nghĩa là nó được thực thi mà không bị chen ngang bởi các luồng
khác. Nói cách khác, không một luồng nào khác có thể truy cập vào địa chỉ này cho tới
khi thao tác kết thúc. Ví dụ, hàm nguyên tử mà chúng ta sẽ sử dụng ở đây là
atomicAdd(), hàm này đọc một từ 32 bit ở một địa chỉ toàn cục hoặc shared, cộng một
số nguyên vào đó, và ghi kết quả trở lại địa chỉ. Trong toàn bộ quá trình này, chỉ có
luồng thực hiện lệnh atomicAdd này là được truy cập vào địa chỉ tương ứng, điều đó
đảm bảo cho kết quả là nhất quán giữa các phép cộng.
Ngoài atomicAdd, CUDA còn cung cấp các hàm nguyên tử khác mà chúng ta không dùng tới: atomicSub, atomicExch, atomicMin, atomicMax,…
Tuy nhiên, có một vấn đề nghiêm trọng khi áp dụng hàm nguyên tử để tính toán
PageRank, đó là các hàm nguyên tử chỉ dùng được cho các số nguyên. Trong khi đó
các giá trị PageRank mà chúng ta tính được là các giá trị thực nằm trong khoảng (0, 1)
(vì PageRank là tỷ lệ thời gian mà người duyệt web dừng lại ở một trang xác định nào
đó). Để khắc phục vấn đề này, chúng ta sẽ biến đổi các giá trị PageRank thành các giá
trị nguyên mà không làm ảnh hưởng tới độ chính xác yêu cầu của bài toán. Ta định
nghĩa vectơ PageRank mới là ( )k T : ( ) w ( ) 10 k T k T Tức là ( )k T chình là giá trị của ( )k T
với dấu phẩy được "dịch" phải w chữ số. Nhân cả
hai vế của công thức với 10w, ta được:
( 1) ( ) ( ) w
( a (1 )10 )e /
k T k T k T T
H n
Lúc này mọi tính toán được thực hiện trên vectơ T
thay vì T
. Các phép chia cũng được làm tròn về số nguyên. Càng dịch phải nhiều thì độ chính xác mà ( )k T
biểu diễn
được càng nhiều nhưng ( )k T
chọn tham số w một cách hợp lý để vẫn đảm bảo độ chính xác của các phép toán mà không gây ra tràn số. Ví dụ, với n = 1.000.000, các phép chia trong công thức có độ
chính xác tới 6 số sau dấu phẩy, khi đó ta chọn w = 6. Vì các giá trị PageRank ban đầu
T
nằm trong khoảng (0, 1) nên với giá trị w đã chọn này thì các giá trị T
sẽ nằm trong
khoảng (0, 106), khoảng này là an toàn cho các phép toán trong công thức.