Chương 5: Xây dựng môi trường lập trình (Programming environment / プログラミング環境) GPU trên Raspberry Pi

Estimated reading: 22 minutes 28 views

Từ việc cài đặt Ubuntu 24.10 đến quá trình cài đặt phần mềm lớp tương thích (Compatibility layer / 互換レイヤ) OpenCL clvk.

_____________________

Bảng 1: Phần cứng có thể dùng để thử nghiệm nội dung của Phần 2

Có thể chạy thử trên các phần cứng (Hardware / ハードウェア) được hỗ trợ bởi thư viện cung cấp Vulkan API libvulkan_broadcom.so

Tên bo mạch (Board name)GPUGhi chú (Remarks)
Raspberry Pi 4 Model BVideoCore VI (Broadcom)Tác giả sử dụng phiên bản 4 GByte
Raspberry Pi 5VideoCore VII (Broadcom)Tác giả sử dụng phiên bản 8 GByte

Phần cứng (Hardware / ハードウェア) tương thích với chương trình mẫu (Sample program / サンプル・プログラム) mà chúng ta sẽ tạo ra lần này là Raspberry Pi 4/5. Lý do là vì thư viện cung cấp Vulkan API libvulkan_broadcom.so chỉ hỗ trợ duy nhất các GPU được liệt kê trong Bảng 1.

1. Bước ①… Cài đặt OS

● Tải về và ghi tập tin ảnh (Image file / イメージ・ファイル)

Truy cập vào trang web của Canonical như chỉ ra ở Bảng 2, nhấn vào nút [Download Ubuntu Desktop 24.10] như Hình 1 để tải về tập tin ảnh dùng cho việc cài đặt Ubuntu 24.10 for Raspberry Pi.

Bảng 2: Nguồn tải hệ điều hành (OS) sẽ sử dụng và liên kết đến tập tin ảnh (Image file / イメージ・ファイル)

Hạng mụcNội dung
Nguồn tảihttps://ubuntu.com/download/raspberry-pi hoặc https://cdimage.ubuntu.com/releases/24.10/release
Giải thíchThe latest version of the Ubuntu operating system for desktop PCs and laptops
Liên kết (Link)https://cdimage.ubuntu.com/releases/24.10/release/ubuntu-24.10-preinstalled-desktop-arm64+raspi.img.xz
Dòng máy hỗ trợRaspberry Pi 3/4/5/Zero 2, ComputeModule 4

Ghi tập tin ảnh đã tải về vào thẻ microSD. Thông tin về cách ghi có rất nhiều trên Internet nên tôi xin phép bỏ qua phần giải thích chi tiết ở đây. Phương pháp cài đặt được Ubuntu khuyến nghị là sử dụng phần mềm Raspberry Pi Imager. Khi dùng phần mềm này để ghi tập tin ảnh đã tải, bạn cần nhấn nút chọn [OS], sau đó kéo xuống dưới cùng của danh sách lựa chọn hiển thị ra và chọn mục [Use custom] (Hình 2).

Hình 1: Trang tải Ubuntu 24.10 for Raspberry Pi

Trang web của công ty Canonical

Hình 2: Cách ghi tập tin ảnh (Image file / イメージ・ファイル) đã tải về bằng phần mềm Raspberry Pi Imager

Chú thích 1: Tải phần mềm tại https://www.raspberrypi.com/software

● Trường hợp OS không khởi động thành công

Theo như tôi đã thử nghiệm thực tế, nếu cài Ubuntu 24.10 lên thẻ microSD rồi cắm trực tiếp vào khe cắm thẻ của Raspberry Pi 4/5 để khởi động, sẽ xảy ra hiện tượng bị treo (Hang-up / ハングアップ) giữa chừng và hệ điều hành (OS / OS) không thể khởi động bình thường.

Danh sách 1 (List 1): Thông báo lỗi (Error message / エラー・メッセージ) được xác nhận trong lần khởi động đầu tiên

Xảy ra hiện tượng treo máy và không khởi động bình thường khi boot Raspberry Pi bằng thẻ microSD đã ghi Ubuntu 24.10

systemd[1]: local-fs.target: Job tmp.mount/start deleted to break ordering cycle starting with local-fs.target/start
[FAILED] Failed to start systemd-udevd.service - Rule-based Manager for Device Events and Files.

Hiện tượng lỗi đã xảy ra. Khi nhấn phím [ESC] trên bàn phím lúc hiện tượng này xuất hiện, tôi đã có thể kiểm tra được thông báo lỗi (Error message / エラー・メッセージ) như ở Danh sách 1.

▶ Biện pháp khắc phục… Có 2 phương pháp hữu hiệu

Sau khi thử nghiệm đủ mọi cách để xem làm thế nào có thể né được sự cố Ubuntu 24.10 vừa mới cài đặt xong không khởi động bình thường, tôi nhận ra rằng những biện pháp sau đây mang lại hiệu quả:

① Sử dụng USB memory làm phương tiện lưu trữ (Media) cài đặt OS.

② Cắm thẻ microSD vào cổng USB thông qua một đầu đọc thẻ nhớ (Memory card reader / メモリ・カード・リーダ).

Để bạn tham khảo, khi thực hiện biện pháp ②, tôi đã sử dụng đầu đọc thẻ nhớ MR3-C008BK (của hãng ELECOM). Thêm nữa, một khi bạn đã khởi động Ubuntu từ thẻ microSD một lần thông qua cách này và để cho quá trình thiết lập ban đầu (Initial setup / 初期設定) của OS hoàn tất, thì từ những lần sau đó, dù bạn có cắm trực tiếp chiếc thẻ microSD đó vào khe cắm thẻ của Raspberry Pi, hệ điều hành (OS) vẫn sẽ khởi động lên một cách bình thường.

▶ Suy đoán nguyên nhân lỗi

Trong các hệ điều hành dành cho Raspberry Pi, thường có một tiến trình tự động điều chỉnh kích thước phân vùng (Partition size / パーティション・サイズ) sao cho phù hợp với dung lượng của thẻ microSD đang được sử dụng ở ngay lần khởi động OS đầu tiên. Nhiều khả năng là khi cài đặt Ubuntu 24.10, tiến trình điều chỉnh kích thước phân vùng này đã gặp thất bại, dẫn đến kết quả là quá trình khởi động ban đầu của OS bị lỗi.

2. Bước ②… Thiết lập ban đầu (Initial setup) cho OS và cài đặt các phần mềm cần thiết

Để tiến hành các công việc từ đây trở đi, bạn cần phải thiết lập (Setup / 設定) phù hợp để Raspberry Pi có thể truy cập được Internet. Tuy nhiên, tôi xin phép bỏ qua phần hướng dẫn cách thiết lập này.

● Trình tự 1: Cập nhật & Cài đặt phần mềm

Cập nhật toàn bộ hệ điều hành lên các phiên bản phần mềm (Software / ソフトウェア) mới nhất. Trong các ví dụ chạy lệnh (Command / コマンド) dưới đây, nếu ký tự đầu tiên của dòng là $ thì điều đó có nghĩa là chạy lệnh dưới quyền người dùng thông thường. Còn nếu ký tự đầu tiên là #, nó mang ý nghĩa là chạy dưới quyền root (Root privilege / rootユーザ権限).

Bash
# apt update
# apt upgrade
# reboot
$ uname -r
6.11.0-1009-raspi
# apt install openssh-server net-tools screen
# apt install git cmake clang vulkan-tools libvulkan-dev clinfo
# apt install g++ opencl-headers libopencv-core-dev libopencv-imgcodecs-dev

Trong quá trình cài đặt openssh-server, nếu bạn được hỏi “What do you want to do about modified configuration file sshd_config?” (File sshd_config đã bị thay đổi nội dung, bạn muốn sử dụng file nào?), hãy chọn tùy chọn “install the package maintainer’s version”.

● Trình tự 2: Cấp quyền sử dụng thiết bị GPU

Để có được quyền sử dụng thiết bị GPU (GPU device / GPUデバイス), hãy thêm User ID của bạn vào nhóm (Group) video và render. Vui lòng thay thế phần <userid> bằng User ID của chính bạn. Ví dụ, nếu User ID là motohashi, bạn hãy nhập vào lệnh “adduser motohashi video”.

Bash
# adduser <userid> video
# adduser <userid> render

Việc thay đổi nhóm trực thuộc sẽ chỉ có hiệu lực từ lần đăng nhập tiếp theo, vì vậy hãy đăng xuất (Log out / ログアウト) khỏi Raspberry Pi một lần, sau đó đăng nhập (Log in / ログイン) lại. Khi bạn chạy lệnh id, danh sách các nhóm người dùng mà bạn đang trực thuộc sẽ hiển thị, hãy kiểm tra xem video và render đã được thêm vào trong đó hay chưa.

Bash
$ id
uid=1000(xxxx) gid=1000(xxxx) groups=1000(xxxx),4(adm),24(cdrom),27(sudo),30(dip),44(video),46(plugdev),100(users),113(lpadmin),123(sambashare),993(render)

3. Bước ③… Lấy mã nguồn (Source code) của phần mềm lớp tương thích (Compatibility layer / 互換レイヤ) OpenCL clvk

● Trình tự 1: Tải mã nguồn (Source code / ソースコード)

Tải mã nguồn của clvk từ GitHub. Tôi thường có thói quen tạo một thư mục (Directory / ディレクトリ) tên là proj ngay dưới thư mục home (Home directory) để làm không gian làm việc (Workspace / ワークスペース) cho việc phát triển phần mềm, nhưng bạn có thể dùng bất kỳ thư mục nào tùy ý.

Bash
$ mkdir proj
$ cd proj
$ git clone https://github.com/kpet/clvk
$ cd clvk

● Trình tự 2: Đồng bộ phiên bản mã nguồn

Các phần mềm trên GitHub có khả năng được cập nhật (Update / 更新) từng ngày. Thời điểm tôi tải mã nguồn của clvk về là lúc thay đổi (Commit) dưới đây vừa được đưa lên kho lưu trữ git (git repository / gitリポジトリ).

Plaintext
commit 85c721767398c136f06f314891341cc69aaea175
Author: Kevin Petit <kpet@free.fr>
Date:   Mon Feb 24 11:56:25 2025 +0000
    Fix FP64 support reporting (#766)

Để nâng cao xác suất các nội dung sẽ được giải thích từ đây trở đi có thể được tái hiện lại y hệt, điều quan trọng là bạn phải điều chỉnh sao cho phiên bản phần mềm (Software version) sử dụng khớp với bản của tôi. Tôi khuyên bạn nên chạy lệnh dưới đây để đồng bộ phiên bản mã nguồn của clvk mà chúng ta sắp sửa biên dịch (Compile / コンパイル) cho khớp với phiên bản tại thời điểm tôi viết bài này.

Bash
$ git checkout 85c7217
Note: switching to '85c7217'.

Tiếp theo, tải xuống mã nguồn (Source code / ソースコード) của các phần mềm khác mà clvk đang sử dụng. Quá trình này sẽ tốn khá nhiều thời gian, nên bạn hãy kiên nhẫn chờ đợi cho đến khi nó hoàn tất.

Bash
$ git submodule update --init --recursive
$ ./external/clspv/utils/fetch_sources.py --deps llvm

4. Bước ④… Chuẩn bị Build (Biên dịch) clvk

● Trình tự 1: Tạo thêm một Swap file

Quá trình Build (Biên dịch / ビルド) của clvk tốn một khoảng thời gian cực kỳ dài (trong trường hợp của Raspberry Pi 4 là mất khoảng nửa ngày). Thêm vào đó, do quá trình biên dịch (Compile / コンパイル) đòi hỏi một lượng bộ nhớ (Memory / メモリ) đáng kể, nên nếu cứ giữ nguyên trạng thái mặc định sau khi cài OS, tiến trình Build clvk chắc chắn sẽ thất bại. Nguyên nhân là do khi hệ thống phát hiện ra tình trạng thiếu bộ nhớ trầm trọng, nhân Linux (Linux kernel) sẽ kích hoạt OOM-Killer (OOM = Out Of Memory) và tàn nhẫn kết liễu (kill) tiến trình nào đang ngốn nhiều bộ nhớ nhất. Vì vậy, để tránh việc Build thất bại do cạn kiệt bộ nhớ, chúng ta sẽ tạm thời tạo thêm một Swap file.

Bằng cách làm theo Trình tự trong Danh sách 2, ngoài cái Swap file tiêu chuẩn 1 GByte, một cái Swap file có dung lượng 8 GByte khác đã bắt đầu có hiệu lực.

Danh sách 2 (List 2): Thêm tạm thời một Swap file để ngăn chặn lỗi khi Build (Biên dịch) clvk

Với trình tự này, một Swap file dung lượng 8 GByte sẽ được thêm vào

Bash
# swapon --show
NAME      TYPE  SIZE USED PRIO
/swapfile file 1024M 59.2M  -2
# cd /
# fallocate -l 8G swapfile2
# chmod 600 swapfile2
# mkswap /swapfile2
Setting up swapspace version 1, size = 4 GiB
                                (4294963200 bytes)
no label, UUID=3c03c6ec-33a8-4e34-8d5e-fe13f41442cf
# swapon swapfile2
# swapon --show
NAME      TYPE  SIZE USED PRIO
/swapfile file 1024M   4M   -2
/swapfile2 file   8G   0B   -3
# free -m
               total        used        free      shared  buff/cache   available
Mem:            3782        1272         159         136        2675        2510
Swap:           9215         672        8543

● Trình tự 2: Đổi trình biên dịch C (C Compiler / Cコンパイラ)

Danh sách 3 (List 3): Chuyển đổi trình biên dịch C (C Compiler) sẽ sử dụng

Mặc định hệ thống đang dùng gcc, ta sẽ chuyển sang clang

Bash
# update-alternatives --list cc
/usr/bin/clang
/usr/bin/gcc
# update-alternatives --config cc
There are 2 choices for the alternative cc (providing /usr/bin/cc).

  Selection    Path             Priority   Status
------------------------------------------------------------
* 0            /usr/bin/gcc      20        auto mode
  1            /usr/bin/clang    10        manual mode
  2            /usr/bin/gcc      20        manual mode

Press <enter> to keep the current choice[*], or type selection number: 1
update-alternatives: using /usr/bin/clang to provide /usr/bin/cc (cc) in manual mode

Bằng cách thực hiện các bước trong Danh sách 3, chúng ta sẽ chuyển đổi trình biên dịch C từ gcc (mặc định của Ubuntu) sang dùng clang. Lý do là vì nếu dùng gcc để Build clvk, sẽ có một lỗi biên dịch (Compile error / コンパイル・エラー) phát sinh và quá trình Build không thể vượt qua được. Tương tự, đối với trình biên dịch C++ (C++ Compiler), hãy làm theo các bước trong Danh sách 4 để chuyển từ g++ sang dùng clang++.

Danh sách 4 (List 4): Chuyển đổi trình biên dịch C++ (C++ Compiler) sẽ sử dụng

Mặc định hệ thống đang dùng g++, ta sẽ chuyển sang clang++

Bash
# update-alternatives --list c++
/usr/bin/clang++
/usr/bin/g++
# update-alternatives --config c++
There are 2 choices for the alternative c++ (providing /usr/bin/c++).

  Selection    Path               Priority   Status
------------------------------------------------------------
* 0            /usr/bin/g++        20        auto mode
  1            /usr/bin/clang++    10        manual mode
  2            /usr/bin/g++        20        manual mode

Press <enter> to keep the current choice[*], or type selection number: 1
update-alternatives: using /usr/bin/clang++ to provide /usr/bin/c++ (c++) in manual mode

Để chắc ăn, hãy chạy thử lệnh cc và lệnh c++ để kiểm tra xem clang có thực sự được gọi lên hay không.

Bash
$ cc --version
Ubuntu clang version 19.1.1 (1ubuntu1)
Target: aarch64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-19/bin
$ c++ --version
Ubuntu clang version 19.1.1 (1ubuntu1)
Target: aarch64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-19/bin

5. Bước ⑤… Build (Biên dịch) clvk

● Trình tự 1: Sinh file Makefile

Chạy lệnh cmake để sinh ra file Makefile cần thiết cho việc Build clvk.

Bash
$ cd ~/proj/clvk
$ mkdir build
$ cd build
$ cmake ..

Nếu có bất kỳ lỗi (Error) nào phát sinh trong lúc chạy cmake, hãy đọc kỹ dòng thông báo lỗi (Error message / エラー・メッセージ) và cố gắng tìm cách sửa nguyên nhân gây ra lỗi. Khi bạn định chạy lại cmake, trước tiên hãy xóa bỏ hoàn toàn thư mục build, sau đó mới thực thi lại lệnh cmake.

Bash
$ cd ..
$ rm -rf build
$ mkdir build
$ cd build
$ cmake ..

● Trình tự 2: Chạy lệnh make

Chạy lệnh make.

<Nếu bộ nhớ (Memory) cài đặt từ 4 GByte trở xuống>

Bash
$ make

<Nếu bộ nhớ (Memory) cài đặt từ 8 GByte trở lên>

Bash
$ make -j2

Khi thanh tiến trình do lệnh cmake hiển thị chạy đến mức 100%, và nếu ở phần cuối cùng xuất hiện các thông báo (Message / メッセージ) giống như Danh sách 5, tức là quá trình Build (Biên dịch / ビルド) của clvk đã hoàn thành vô sự.

Danh sách 5 (List 5): Thông báo (Message) khi quá trình Build clvk hoàn tất

Plaintext
[ 96%] Built target OpenCL-objects
[ 96%] Linking CXX static library libOpenCL-static.a
[ 96%] Linking CXX shared library ../libOpenCL.so
[100%] Linking CXX executable ../../api_tests
[100%] Built target api_tests
[100%] Linking CXX executable ../../simple_test_from_il_binary
[100%] Built target simple_test_from_il_binary

:
: Một lượng thông báo đồ sộ (Nếu dòng thông báo như dưới đây hiện ra tức là đã thành công mỹ mãn)
:
-- Configuring done (134.2s)
-- Generating done (37.1s)
-- Build files have been written to: /home/motohashi/proj/clvk/build

Thành quả Build (Build artifact) mà chúng ta thực sự cần chỉ là 2 file: libOpenCL.so.0.1 và clspv. Các file thực thi (Executable file / 実行ファイル) khác (chủ yếu là các chương trình dùng để test clvk) dẫu có sinh ra lỗi khi Build đi chăng nữa thì bạn cứ phớt lờ đi cũng chẳng có vấn đề gì.

● Về lỗi khi Build (Build error)

Nếu hệ thống cạn kiệt bộ nhớ trong lúc đang biên dịch (Compile / コンパイル) clvk, màn hình sẽ văng ra một thông báo lỗi (Error message / エラー・メッセージ) giống như Danh sách 6(a) và quá trình Build sẽ bị gián đoạn.

Để xác minh xem liệu nguyên nhân của cái lỗi này có thực sự là do thiếu bộ nhớ hay không, cách chắc chắn nhất là chạy lệnh dmesg để kiểm tra nhật ký nhân hệ thống (Kernel log / カーネル・ログ) như trong Danh sách 6(b).

Từ dòng thông báo c++ invoked oom-killer, chúng ta hiểu được rằng oom-killer đã được kích hoạt, và thủ phạm gây ra tình trạng thiếu bộ nhớ hệ thống chính là tiến trình (Process / プロセス) của c++ đã bị đem ra hành hình (kill). Nếu gặp phải hiện tượng này, hãy thử các biện pháp xử lý sau:

・Giảm số lượng tiến trình song song (Parallel job) khi Build (Bỏ tùy chọn -j2 đi).

・Tăng thêm dung lượng cho cái Swap file (スワップ・ファイル).

Danh sách 6 (List 6): Ví dụ về Thông báo lỗi (Error message) hiển thị khi Build clvk

(a) Ví dụ về Thông báo lỗi

Plaintext
[ 48%] Building CXX object external/SPIRV-LLVM-Translator/lib/SPIRV/CMakeFiles/LLVMSPIRVLib.dir/libSPIRV/SPIRVEntry.cpp.o
Killed
make[2]: *** [external/SPIRV-LLVM-Translator/lib/SPIRV/CMakeFiles/LLVMSPIRVLib.dir/build.make:524: external/SPIRV-LLVM-Translator/lib/SPIRV/CMakeFiles/LLVMSPIRVLib.dir/libSPIRV/SPIRVEntry.cpp.o] Error 137
make[1]: *** [CMakeFiles/Makefile2:256616: external/SPIRV-LLVM-Translator/lib/SPIRV/CMakeFiles/LLVMSPIRVLib.dir/all] Error 2
make: *** [Makefile:156: all] Error 2

(b) Cảnh tượng kiểm tra Kernel log bằng lệnh dmesg

Plaintext
# dmesg | less
Nhập chuỗi /oom-kill rồi nhấn [Enter] để tìm kiếm từ khóa oom-kill
[37934.484695] c++ invoked oom-killer: gfp_mask=0x440dc0(GFP_KERNEL_ACCOUNT|__GFP_COMP|__GFP_ZERO), order=0, oom_score_adj=0

6. Bước ⑥… Cài đặt (Install) clvk

Cài đặt các tập tin nhị phân (Binary file / バイナリ・ファイル) đã ra lò vào hệ thống.

Bash
$ sudo make install
  :
Install the project...
-- Install configuration: "RelWithDebInfo"
-- Installing: /usr/local/libOpenCL.so.0.1
-- Installing: /usr/local/libOpenCL.so.1
-- Installing: /usr/local/libOpenCL.so
-- Installing: /usr/local/clspv

Vì các tập tin nhị phân như libOpenCL.so sẽ bị ném thẳng vào thư mục /usr/local, nên chúng ta sẽ phải thủ công di chuyển chúng vào thư mục /usr/local/lib.

Bash
# cd /usr/local
# mv clspv libOpenCL.so* lib

Nếu cứ để y nguyên như thế này, các chương trình ứng dụng sử dụng OpenCL sẽ không tài nào tìm thấy file libOpenCL.so của clvk. Do đó, chúng ta cần phải đăng ký (Register / 登録) file libOpenCL.so của clvk vào ICD Loader của OpenCL. Trình nạp ICD Loader (Installable Client Driver) là một cơ chế quản lý môi trường thực thi của OpenCL, với sứ mệnh cung cấp sự hỗ trợ cho hàng loạt các bản triển khai OpenCL khác nhau (Nói tóm lại chính là hỗ trợ các file libOpenCL.so được cung cấp bởi đủ các hãng sản xuất GPU trên thị trường).

Bash
# mkdir -p /etc/OpenCL/vendors
# echo /usr/local/lib/libOpenCL.so.1 > /etc/OpenCL/vendors/clvk.icd

7. Bước ⑦… Kiểm tra hoạt động của clvk

Chạy lệnh clinfo để xác nhận xem clvk đã hoạt động trơn tru hay chưa. clinfo là một chương trình tiện ích (Utility program / ユーティリティ・プログラム) dùng để liệt kê các Nền tảng OpenCL (OpenCL platform / OpenCLプラットフォーム) (ví dụ như Nền tảng của NVIDIA hay AMD) và tên thiết bị (ví dụ như mã model của card đồ họa) đang cắm rễ trên hệ thống. Ví dụ về kết quả hiển thị được mô tả ở Danh sách 7.

Danh sách 7 (List 7): Ví dụ chạy lệnh clinfo

Lệnh này sẽ hiển thị danh sách các Nền tảng OpenCL (OpenCL platform) và Tên thiết bị (Device name) đang tồn tại trên hệ thống

Plaintext
$ clinfo
Number of platforms  1
  Platform Name      clvk
  Platform Vendor    clvk
  Platform Version   OpenCL 3.0 clvk
  Platform Profile   FULL_PROFILE

Number of devices    2

  Device Name        V3D 7.1.7.0
  Device Vendor      Unknown vendor
  Device Vendor ID   0x14e4
  Device Version     OpenCL 3.0 CLVK on Vulkan v1.2.289 driver 100671496
    :
  Device Name        llvmpipe (LLVM 19.1.1, 128 bits)
  Device Vendor      Mesa
  Device Vendor ID   0x10005
  Device Version     OpenCL 3.0 CLVK on Vulkan v1.3.289 driver 1

Như bạn có thể thấy, nếu ở phần Device Name có hiển thị chữ V3D thì coi như là ngon nghẻ (OK). Trong trường hợp việc cấu hình nhóm cho User ID bị thực hiện sai cách, một lỗi (Error / エラー) sẽ bung bét ra ngay khi bạn gọi lệnh clinfo.

Leave a Comment

Chia sẻ:

Chương 5: Xây dựng môi trường lập trình (Programming environment / プログラミング環境) GPU trên Raspberry Pi

Or copy link

CONTENTS