Tệp thứ tự là một kỹ thuật tối ưu hoá trình liên kết gần đây. Các tệp thứ tự này là tệp văn bản chứa những biểu tượng đại diện cho các hàm. Các trình liên kết như lld dùng tệp thứ tự để bố trí các hàm theo thứ tự cụ thể. Các tệp nhị phân hoặc thư viện có biểu tượng xếp theo thứ tự giúp giảm lỗi trang, đồng thời cải thiện thời gian khởi động chương trình nhờ tải biểu tượng nhanh chóng trong quá trình khởi động nguội của chương trình.
Bạn có thể thêm các tính năng của tệp thứ tự vào ứng dụng bằng cách làm theo 3 bước sau:
- Tạo tệp các cấu hình và ánh xạ
- Tạo một tệp thứ tự từ tệp các cấu hình và ánh xạ
- Dùng tệp thứ tự trong Bản phát hành để sắp xếp các biểu tượng
Tạo tệp thứ tự
Quy trình tạo một tệp thứ tự cần 3 bước sau:
- Xây dựng một phiên bản được đo lường của ứng dụng ghi tệp thứ tự
- Chạy ứng dụng đó để tạo các cấu hình
- Hậu xử lý tệp các cấu hình và ánh xạ
Tạo một bản dựng được đo lường
Các cấu hình được tạo bằng cách chạy một bản dựng được đo lường của ứng dụng.
Để chạy một bản dựng được đo lường, bạn phải thêm -forder-file-instrumentation
vào cả cờ trình biên dịch lẫn cờ trình liên kết và thêm -mllvm -orderfile-write-mapping=<filename>-mapping.txt
vào cờ trình biên dịch một cách nghiêm ngặt.
Cờ khả năng đo lường cho phép đo lường tệp thứ tự để phân tích và tải thư viện cụ thể cần thiết cho việc phân tích.
Mặt khác, cờ ánh xạ chỉ xuất tệp ánh xạ hiển thị hàm băm MD5 cho từng hàm trong tệp nhị phân hoặc thư viện.
Ngoài ra, hãy nhớ truyền mọi cờ tối ưu hoá ngoại trừ -O0
, vì cả cờ khả năng đo lường lẫn cờ ánh xạ đều cần có một cờ tối ưu hoá.
Nếu bạn không truyền cờ tối ưu hoá nào, tệp ánh xạ sẽ không được tạo và bản dựng được đo lường có thể xuất hàm băm không chính xác sang tệp cấu hình.
ndk-build
Hãy nhớ tạo bằng APP_OPTIM=release
để ndk-build sử dụng chế độ tối ưu hoá không phải -O0
. Khi tạo bằng AGP, thao tác này sẽ tự động áp dụng cho các bản phát hành.
LOCAL_CFLAGS += \
-forder-file-instrumentation \
-mllvm -orderfile-write-mapping=mapping.txt \
LOCAL_LDFLAGS += -forder-file-instrumentation
CMake
Hãy nhớ dùng CMAKE_BUILD_TYPE
thay vì Debug
để CMake sử dụng chế độ tối ưu hoá không phải -O0
. Khi tạo bằng AGP, thao tác này sẽ tự động áp dụng cho các bản phát hành.
target_compile_options(orderfiledemo PRIVATE
-forder-file-instrumentation
-mllvm -orderfile-write-mapping=mapping.txt
)
target_link_options(orderfiledemo PRIVATE -forder-file-instrumentation)
Các hệ thống xây dựng khác
Biên dịch mã bằng -forder-file-instrumentation -O1 -mllvm
-orderfile-write-mapping=mapping.txt
.
Bạn không bắt buộc phải sử dụng -O1
, nhưng đừng dùng -O0
.
Bỏ qua -mllvm -orderfile-write-mapping=mapping.txt
khi liên kết.
Tất cả những cờ này không cần thiết cho một Bản phát hành. Vì vậy, bạn phải kiểm soát bản phát hành này bằng một biến thể bản dựng. Để đơn giản, bạn có thể thiết lập tất cả trong CMakeLists.txt như trong mẫu của chúng tôi.
Tạo một thư viện tệp thứ tự
Ngoài các cờ, tệp cấu hình cần được thiết lập và tệp nhị phân được đo lường cần kích hoạt rõ ràng một lượt ghi cấu hình trong quá trình thực thi tệp đó.
- Gọi
__llvm_profile_set_filename(PROFILE_DIR "/<filename>-%m.profraw")
để thiết lập đường dẫn cấu hình. Mặc dù đối số được truyền là<filename>-%m.profraw
, tệp cấu hình sẽ được lưu dưới dạng<filename>-%m.profraw.order
. Đảm bảo ứng dụng có thể ghiPROFILE_DIR
và bạn có quyền truy cập vào thư mục này.- Do nhiều thư viện chia sẻ được lập cấu hình,
%m
rất hữu ích vì mở rộng thành một chữ ký mô-đun duy nhất cho thư viện, giúp lập một cấu hình riêng cho mỗi thư viện. Để biết thêm thông số mẫu, bạn có thể xem đường liên kết này.
- Do nhiều thư viện chia sẻ được lập cấu hình,
- Gọi
__llvm_profile_initialize_file()
để thiết lập tệp cấu hình - Gọi
__llvm_orderfile_dump()
để ghi rõ ràng vào tệp cấu hình
Các cấu hình được thu thập trong bộ nhớ và chức năng kết xuất ghi các cấu hình đó vào tệp. Bạn cần đảm bảo hàm kết xuất được gọi ở cuối quá trình khởi động để tệp cấu hình có tất cả các biểu tượng cho đến khi khởi động xong.
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_initialize_file(void);
extern int __llvm_orderfile_dump(void);
}
#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
// ...
// run workload
// ...
// set path and write profiles after workload execution
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
__llvm_profile_initialize_file();
__llvm_orderfile_dump();
return;
}
Chạy bản dựng cho các cấu hình
Chạy ứng dụng được đo lường trên một thiết bị thực hoặc ảo để tạo các cấu hình.
Bạn có thể trích xuất các tệp cấu hình bằng adb pull
.
adb shell "run-as <package-name> sh -c 'cat /data/user/0/<package-name>/cache/default-%m.profraw.order' | cat > /data/local/tmp/default-%m.profraw.order"
adb pull /data/local/tmp/default-%m.profraw.order .
Như đã đề cập trước đó, hãy đảm bảo rằng bạn có thể truy cập vào thư mục chứa tệp cấu hình đã ghi. Nếu đó là một thiết bị ảo, bạn không nên dùng trình mô phỏng chứa Cửa hàng Play do không có quyền truy cập vào nhiều thư mục.
Hậu xử lý tệp cấu hình và ánh xạ
Khi tải các cấu hình, bạn cần tìm tệp ánh xạ và chuyển đổi từng cấu hình sang định dạng hệ thập lục phân. Thông thường, bạn có thể tìm thấy tệp ánh xạ trong thư mục bản dựng của ứng dụng. Khi đã có cả hai, bạn có thể dùng tập lệnh để lấy tệp cấu hình và tệp ánh xạ chính xác nhằm tạo một tệp thứ tự.
Linux/Mac/ChromeOS
hexdump -C default-%m.profraw.order > default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt
Windows
certutil -f -encodeHex default-%m.profraw.order default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt
Nếu muốn đọc thêm về tập lệnh, bạn có thể xem tệp README này.
Dùng tệp thứ tự để tạo ứng dụng
Sau khi tạo một tệp thứ tự, bạn nên xoá các cờ cũ và các hàm của tệp thứ tự đó vì chúng chỉ dành cho các bước tạo.
Bạn chỉ cần truyền -Wl,--symbol-ordering-file=<filename>.orderfile
vào cờ biên dịch và cờ trình liên kết.
Đôi khi, bạn sẽ không tìm thấy biểu tượng hoặc không thể di chuyển và đưa ra cảnh báo để có thể truyền -Wl,--no-warn-symbol-ordering
nhằm loại bỏ những cảnh báo này.
ndk-build
LOCAL_CFLAGS += \
-Wl,--symbol-ordering-file=<filename>.orderfile \
-Wl,--no-warn-symbol-ordering \
LOCAL_LDFLAGS += \
-Wl,--symbol-ordering-file=<filename>.orderfile \
-Wl,--no-warn-symbol-ordering \
CMake
target_compile_options(orderfiledemo PRIVATE
-Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
)
target_link_options(orderfiledemo PRIVATE
-Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
)
Các hệ thống xây dựng khác
Biên dịch mã bằng -Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
.
Để biết thêm thông tin, hãy xem ví dụ về tệp thứ tự.
Thông tin chi tiết về việc triển khai tệp thứ tự
Có nhiều cách tạo các tệp đơn hàng và dùng các tệp đó để xây dựng. NDK sử dụng phương thức của LLVM. Vì vậy, đây là phương thức hữu ích nhất đối với các thư viện chia sẻ C hoặc C++ của bạn trên ứng dụng Java hoặc Kotlin thực tế. Clang nhận mọi tên hàm (biểu tượng), tạo một hàm băm MD5 để xử lý và xuất mối quan hệ này sang một tệp ánh xạ. Hàm băm MD5 của một hàm được ghi vào tệp cấu hình (định dạng profraw) khi hàm này thực thi lần đầu tiên. Mọi quá trình thực thi tiếp theo của hàm sẽ không ghi hàm băm MD5 vào tệp cấu hình vì hàm này muốn tránh trùng lặp. Do đó, chỉ lần thực thi đầu tiên của hàm được ghi lại vào thứ tự. Bằng cách xem qua tệp cấu hình và tệp ánh xạ, bạn có thể lấy từng hàm băm MD5 và thay thế bằng hàm tương ứng rồi nhận tệp thứ tự.
Bạn có thể tìm thấy các ví dụ về cả tệp hồ sơ ở định dạng hệ thập lục phân và tệp ánh xạ lần lượt là example.prof và example-mapping.txt.