Tối ưu hóa khởi động Pi đến mức cực hạn
(kittenlabs.de)- SolarCamPi là camera năng lượng mặt trời off-grid chỉ bật Raspberry Pi Zero 2 W khi chụp ảnh rồi tắt đi, nên thời gian khởi động ảnh hưởng trực tiếp đến tuổi thọ pin
- Với Debian 12 arm64 Lite, khi đo
/init.shlàm mã không gian người dùng đầu tiên, lần khởi động ban đầu mất khoảng 12 giây và tiêu thụ 9.5Ws - Bằng cách cắt giảm HDMI, LED, HAT/PoE/LCD, tự động phát hiện camera·màn hình và initramfs, các khoảng chờ và cơ chế dò tìm không cần thiết được loại bỏ, dòng điện giảm từ 136.7mA → 120.6mA
- Sau khi chuyển sang Buildroot 2024.02.1 và kernel tùy biến, loại bỏ driver, nén, KASLR và một số cơ chế giảm thiểu, hệ thống đạt tới chương trình không gian người dùng Linux trong dưới 3.5 giây
- Khi hạ điện áp đầu vào từ 5.0V xuống 3.6V, tổng năng lượng giảm từ 1.754Ws → 1.438Ws, nhưng đây là vận hành ngoài đặc tả nên vẫn cần kiểm chứng về độ ổn định và độ tin cậy
Vì sao SolarCamPi phải giảm thời gian khởi động
- SolarCamPi là camera WiFi chạy bằng năng lượng mặt trời, định kỳ khởi động Raspberry Pi Zero 2 W để chụp ảnh, tải ảnh lên dịch vụ đám mây qua WiFi rồi lại tắt máy
- Trong những môi trường thiếu điện như mùa đông ở Tây Âu, mỗi giây Pi bật lên đều tương đương với chi phí năng lượng
- Ứng dụng không gian người dùng cho việc kết nối máy chủ và tải ảnh lên đã được tối ưu hết mức có thể, và mạch điện tử cũng đã được thiết kế để giảm điện năng khi ngủ
- Còn lại hai hướng tiết kiệm
- Giảm dòng điện tiêu thụ
- Giảm thời gian thực thi
- Chỉ giảm dòng điện không phải lúc nào cũng có lợi
- Ví dụ tắt CPU turbo có thể làm dòng điện giảm, nhưng nếu thời gian chạy tăng thì tổng năng lượng lại có thể lớn hơn
- Mục tiêu là tối thiểu hóa diện tích dưới đồ thị dòng điện và thời gian
Thiết bị đo và cách thử nghiệm
- Trong tối ưu khởi động hệ thống nhúng, việc nhanh chóng kiểm tra chạy thực tế sau mỗi thay đổi là rất quan trọng, nên các công cụ giúp giảm thao tác tháo SD card và bật tắt nguồn là cần thiết
- Thiết bị sử dụng gồm
- Nordic Power Profiler Kit II
- USB-SD-Mux Fast
- Bộ chuyển đổi USB-UART
- Power Profiler Kit II vừa cấp nguồn cho thiết bị đang thử nghiệm vừa đo mức tiêu thụ điện theo thời gian và trạng thái của 8 ngõ vào số
- Chân GPIO của Raspberry Pi được nối vào các ngõ vào số
- Ở hành động đầu tiên của ứng dụng, GPIO được toggle để đo thời gian từ lúc cấp nguồn đến khi mã không gian người dùng bắt đầu chạy
- USB-SD-Mux là một interposer nằm giữa thẻ microSD và thiết bị, cho phép máy tính lấy thẻ về, ghi lại nội dung rồi trả nó cho thiết bị
- Loại bỏ vòng lặp phải rút thẻ, cắm vào đầu đọc rồi lại lắp vào thiết bị
- GPIO on-board cũng có thể tự động hóa việc reset hoặc điều khiển nguồn của thiết bị thử nghiệm
- Console USB-UART cần thiết để kiểm tra trạng thái khi hệ thống hỏng, chẳng hạn lỗi khởi động hoặc sự cố WiFi
Đo khởi động với Debian
- Trên ảnh Debian 12 bookworm arm64 Lite sạch, thêm
init=/init.shvào/boot/firmware/cmdline.txt - Thiết lập này khiến kernel chạy
/init.shnhư tiến trình đầu tiên của không gian người dùng trước cả systemd - Ví dụ
init.shsẽ toggle GPIO4 rồiexec /sbin/initđể tiếp tục quá trình khởi động systemd - Ở phép đo ban đầu, sau khoảng 12 giây ngõ vào số 0 chuyển xuống low, xác nhận
init.shđã được chạy - Quá trình khởi động này dùng tổng cộng 1.90 coulomb
1.9As * 5.0V = 9.5Ws- Một pin alkaline AA có thể cung cấp khoảng 13500Ws năng lượng
Giảm dòng điện tiêu thụ
- Khi vô hiệu hóa hoàn toàn bộ mã hóa HDMI, dòng điện giảm từ 136.7mA xuống 122.6mA
- Do cần mã hóa dữ liệu camera nên bản thân GPU không thể tắt
- Nếu là ứng dụng không cần camera hay GPU, có thể thử vô hiệu hóa luôn GPU
- Chỉ riêng việc tắt activity LED đã tiết kiệm 2mA, hạ dòng điện từ 122.6mA xuống 120.6mA
- Nếu có LED camera thì cũng có thể vô hiệu hóa
- Điều này cũng giảm khả năng LED phản chiếu vào ảnh
- Trong thử nghiệm thay đổi thiết lập turbo, Pi ở trạng thái cấu hình hiện tại tiêu thụ 1.62As
- Nếu chạy không ép turbo thì tiêu thụ 1.58As
- Vì lý do chưa rõ, khi tắt chế độ turbo/boost thì trạng thái mặc định của GPIO4 bị đảo, nên trong
init.shđã đổi cực tính
Giảm thời gian khởi động
- Dòng điện đã giảm khoảng 13%, nhưng vẫn mất khoảng 8 giây trước khi dòng output Linux đầu tiên xuất hiện trên console, và riêng giai đoạn này đã tiêu thụ khoảng 1As
- Dòng Raspberry Pi khởi tạo GPU trước
- GPU tìm
bootcode.bintrên SD card - Với Pi 4 trở lên thì dùng EEPROM
- GPU tìm
- Nếu bật
BOOT_UARTtrongbootcode.binthì có thể xem log UART chi tiết- Cần sao lưu
bootcode.bingốc, và quá trình chỉnh sửa có thể gây hỏng hệ thống
- Cần sao lưu
- Bootloader cố tự động phát hiện tham số video của màn hình HDMI được kết nối bằng cách chờ phản hồi EDID
- Vì không dùng HDMI nên chuỗi EDID được hardcode để tránh bước dò tìm này
- Việc dò EEPROM I2C liên quan đến HAT, quạt PoE, LCD và màn hình cảm ứng cũng bị vô hiệu hóa
- Các tùy chọn này phải chờ phản hồi trên bus I2C nên nếu không cần thì nên tắt
- Tự động phát hiện camera và màn hình MIPI cũng tốn thời gian
- Vì camera dùng cố định là HQ Camera IMX477 nên tắt bằng
camera_auto_detect=0,display_auto_detect=0và nạp trực tiếpdtoverlay=imx477
- Vì camera dùng cố định là HQ Camera IMX477 nên tắt bằng
- Những thay đổi trên làm thời gian khởi động tự báo giảm từ 5.38 giây xuống 4.75 giây, và khi bỏ
auto_initramfs=1để tắt initramfs thì giảm tiếp xuống 4.47 giây - Cách
sdtweakép xung thiết bị ngoại vi SD lên 100MHz không tạo ra khác biệt hiệu năng khởi động đủ để đo được- Nó có rủi ro hỏng dữ liệu khi ghi, nên không phù hợp với thiết bị IoT từ xa
Nút thắt khi nạp kernel và chuyển sang Buildroot
- Ở giai đoạn này, nạp kernel là một trong những tác vụ chậm nhất
- Mất khoảng 1.54 giây để nạp
kernel8.imgkích thước 9,276,375 byte - Tốc độ truyền khoảng 6MiB/s
- Mất khoảng 1.54 giây để nạp
- Việc nạp kernel do GPU đảm nhiệm, sử dụng bộ xử lý VideoCore IV độc quyền bên trong
- Mã loader có thể kém hiệu quả hoặc dùng thiết lập quá thận trọng, nhưng vì đây là hộp đen nên không thể tinh chỉnh thanh ghi hay tham số theo cách hữu ích
- Về lý thuyết có thể ép xung lõi xử lý GPU, và điều đó giúp giảm thời gian nạp kernel khoảng 20%
- Tuy nhiên không rõ các tác dụng phụ như độ tin cậy, nên không được khuyến nghị
- Hệ thống được chuyển từ Raspbian/Debian sang bản phân phối tùy biến dựa trên Buildroot 2024.02.1
- Dùng toolchain native aarch64
- Vẫn giữ glibc và các công cụ userland của Raspberry Pi
- Trong kernel tùy biến, các thành phần sau đã bị loại bỏ hoặc cắt giảm
- Hỗ trợ âm thanh
- Hầu hết driver thiết bị khối và filesystem, chỉ giữ SD/MMC và ext4
- RAID, USB, HID, DVB
- Hỗ trợ video và framebuffer
- Các tính năng mạng nâng cao như tunnel, bridging, firewall
- Nén kernel bằng Gzip và nén module
- Cách không nén cả kernel lẫn module mang lại lợi ích về tổng năng lượng dù GPU phải nạp lâu hơn
- Giải nén Gzip tiêu tốn nhiều năng lượng và trên thực tế gần như bao gồm thêm một bước relocation
- KASLR cũng bị vô hiệu hóa
- KASLR ngẫu nhiên hóa địa chỉ nạp kernel trong bộ nhớ để khiến việc viết exploit khó hơn, nhưng sau khi GPU nạp xong thì kernel phải được relocation
- Trong trường hợp sử dụng này, bề mặt tấn công qua mạng rất hạn chế và toàn bộ phần mềm ứng dụng đều chạy bằng root
- Các cơ chế giảm thiểu lỗ hổng thực thi suy đoán như Spectre cũng bị tắt
- Kernel kết quả có kích thước 8.5MiB không nén, còn bản nén Gzip để so sánh là 4.1MiB
- Kernel Raspbian gốc là 25MiB không nén, 8.9MiB nén Gzip
Kết quả cuối cùng và tối ưu điện áp đầu vào
- Cuối cùng hệ thống đạt tới chương trình không gian người dùng Linux trong dưới 3.5 giây
- Thời gian bên trong Linux kernel sử dụng chỉ khoảng 400ms
- Tổng năng lượng tiêu thụ là 0.364As * 5.0V = 1.82Ws
- So với mức 9.5Ws để vào được không gian người dùng trên Debian mặc định, đây chỉ còn khoảng 1/5
- Sau khi bài viết được đăng, Graham Sutherland / Polynomial chỉ ra rằng regulator của Pi Zero không hiệu quả khi đầu vào là 5.0V
- Trong kịch bản thử nghiệm và cả sản phẩm hoàn chỉnh, điện áp đầu vào có thể hạ xuống 4.0V
- 5.0V:
350.94mAs * 5.0V = 1.754Ws - 4.0V:
390.77mAs * 4.0V = 1.563Ws - 3.6V:
399.60mAs * 3.6V = 1.438Ws
- 5.0V:
- Khi hạ điện áp, mC tức mAs tăng lên do dòng điện tăng, nhưng tổng năng lượng lại giảm đáng kể
- Vận hành ở 3.6V giúp giảm thêm khoảng 20% năng lượng nhờ dùng switching regulator ở điểm hoạt động lý tưởng hơn, nhưng về mặt kỹ thuật đây là ngoài đặc tả nên cần kiểm chứng thêm về độ ổn định và độ tin cậy
Cấu hình và mã đã công khai
- SolarCamPi config.txt: toàn bộ
config.txt - SolarCamPi Linux kernel defconfig: cấu hình kernel đã được tinh gọn
- SolarCamPi-Buildroot v2 branch: toàn bộ cây Buildroot, hiện vẫn đang được phát triển
1 bình luận
Các ý kiến trên Hacker News
Quản lý năng lượng của dòng Raspberry Pi rõ ràng là một trong những điểm yếu. Vì vậy tôi khá kỳ vọng vào Pico 2 mới, bởi có vẻ nó dễ đi vào các trạng thái tiết kiệm điện tương đối sâu mà không cần phần cứng bên ngoài
Tôi từng làm một camera cho mục đích tương tự bằng Google Coral mini; camera không tốt bằng HQ cam, nhưng nhờ RTC tích hợp nên hỗ trợ standby/wake rất dễ, rất hợp với các ứng dụng chụp ảnh định kỳ. Nó cũng đủ hiệu năng và có 2GB bộ nhớ để xử lý ảnh độ phân giải cao
Về mặt vật lý có thể kết nối HQ camera, nhưng theo tôi biết thì trên Coral không có pipeline phần mềm để quản lý nó
Hệ sinh thái Raspberry Pi trưởng thành hơn nhiều, và tôi tin tưởng khả năng Raspberry Pi được cung ứng trong tương lai hơn là việc Google sẽ tiếp tục cung cấp dòng Coral. Dù vậy, tôi đã thấy rất rõ hỗ trợ năng lượng tốt ở phần cứng hữu ích đến mức nào
Trớ trêu là phiên bản camera tiếp theo lại được một nhà thầu bên ngoài làm bằng Raspberry Pi, và vấn đề điện năng được bù bằng cách lắp pin lớn hơn nhiều. Nhờ vậy mà tôi đang chất đống 100 chiếc Coral dev mini và camera còn chưa mở hộp, rơi vào cảnh phải tìm ý tưởng hay để dùng hoặc đem bán
Tôi tìm "google coral twitter" để kiếm tài khoản Twitter chính thức, ai ngờ kết quả thứ hai lại là tweet của bạn đang cố bán 100 bo mạch còn dư, thật bối rối
Nghe nói phải quản lý nguồn bằng phần cứng bên ngoài thì có vẻ đây không chỉ là vấn đề phần mềm đơn thuần
Nếu đóng gói ứng dụng thành initramfs được liên kết vào kernel, trong các trường hợp đơn giản có thể giảm khá nhiều vì không cần mount filesystem
Trong một số trường hợp, cả BusyBox init cũng có thể được thay bằng một script bash đơn giản chỉ thực hiện phần boot tối thiểu. Cũng đáng cân nhắc mount devtmpfs, proc, sysfs, v.v., và nếu có thể thì bỏ glibc
Trước khi đóng initramfs vào kernel, nên dùng chroot để kiểm tra xem đã có đủ mọi dependency cần thiết của ứng dụng chưa. Nếu chạy được trong chroot thì kernel cũng có thể chạy nó trong lúc boot, và vòng lặp phát triển sẽ nhanh hơn nhiều
Tắt các kernel module và liên kết thẳng vào kernel chỉ những chức năng cần thiết có thể giảm thêm dung lượng và thời gian boot. Cũng đáng thử nén zstd thay vì gzip
Điều này áp dụng khi các giai đoạn boot trước đó chưa tận dụng đủ hiệu năng phần cứng, hoặc image lớn đến mức vừa tải vừa làm việc khác song song sẽ tốt hơn
Khi đó thứ còn lại chỉ là initramfs chứa một binary được liên kết tĩnh
Có thêm hai bài viết hay về việc giảm thời gian boot của Pi
https://www.furkantokac.com/rpi3-fast-boot-less-than-2-secon...
http://himeshp.blogspot.com/2018/08/fast-boot-with-raspberry...
Tôi đã tham khảo hai bài này để làm khung ảnh kỹ thuật số bằng Pi, và khiến nó boot rất nhanh tới tận trình duyệt chế độ kiosk. Nếu yêu cầu rất ít thì có thể đạt thời gian boot khá ấn tượng
Bi kịch thật sự là mã GPU bootcode.bin là một hộp đen độc quyền và không có mã nguồn
Thật kinh khủng khi các dự án hacking và sở thích cá nhân lại phải mang theo một hộp đen bí mật ẩn mà không thể sửa đổi
Hiện giờ nó là phần mềm tự do nguồn mở
https://www.theregister.com/2023/11/28/microsoft_opens_sourc...
Điều đó không có nghĩa toàn bộ firmware của Pi tự động trở thành tự do nguồn mở, vì chúng không phải là driver. Nhưng nếu muốn thì có thể làm như vậy
Tôi tò mò bên trong có gì mà phải đóng kín như vậy
Mình thích toàn bộ bài viết, nhưng phần này thì chưa chắc lắm
Ý là tắt CPU turbo để tiết kiệm một chút dòng điện là lựa chọn không tốt, vì thời gian bị chậm đi sẽ khiến nó dùng nhiều năng lượng hơn so với việc hoàn tất nhanh rồi tắt
Trong lớp khoa học máy tính, mình học rằng mức tiêu thụ điện năng tỉ lệ với bình phương tần số xung nhịp. Tức là nếu tăng xung nhịp lên gấp đôi thì điện năng sẽ tăng gấp bốn
Nếu vậy, để xác nhận phần tăng bậc hai do tăng xung nhịp có lớn hơn tích của mức tiêu thụ điện cố định phát sinh khi thời gian xử lý kéo dài hay không, có lẽ cần đo chênh lệch điện năng thực tế
Liên quan đến việc này, sẽ rất tốt nếu CPU Pi cung cấp thông tin tiêu thụ điện năng chi tiết có thể suy ra từ datasheet hoặc được phơi bày theo thời gian thực qua register
Hầu hết chip cần điện áp cao hơn để đạt tốc độ xung nhịp cao hơn, nên từ đó mới xuất hiện quan hệ bậc hai
Nhưng theo mình biết Raspberry Pi không có điều khiển điện áp động, nên nếu chỉ hạ xung nhịp mà không hạ điện áp thì có lẽ sẽ không ảnh hưởng đến tổng năng lượng tiêu thụ do chuyển mạch
Tất nhiên cũng có điểm tối ưu. Nếu ép xung CPU quá nhiều, hiệu năng trên mỗi watt sẽ giảm quá mạnh và race to idle không còn hiệu quả nữa
Vì vậy các hệ thống nhúng hiện đại thường dùng chiến lược "race-to-sleep" hoặc "race-to-halt": chạy tác vụ thật nhanh rồi tắt hầu hết thành phần cho đến khi sự kiện tiếp theo đến
Nếu một phép tính cần 1J để thực hiện trong 1 giây, ví dụ 1W ở 1GHz, thì trong mô hình bò hình cầu hoàn hảo, để thực hiện cùng phép tính trong 0,5 giây sẽ cần 2J. Vì ở 2GHz sẽ thành 4W
Tuy nhiên đó chỉ xét mức tiêu thụ của CPU; nếu toàn hệ thống có mức tiêu thụ cố định 4W, thì ở 1GHz sẽ tốn CPU 1J cộng hệ thống 4J, tổng 5J, còn ở 2GHz sẽ tốn CPU 2J cộng hệ thống 2J, tổng 4J
Nếu mình hiểu đúng, điều đó có nghĩa là nếu mức tiêu thụ điện của toàn hệ thống tương đương mức tiêu thụ của CPU ở trạng thái turbo thì nên dùng turbo, còn không thì không?
Ấn tượng thật. Nhưng mỗi lần đọc những bài như thế này mình lại nhớ đến lần ghi lại cảnh Plan 9 boot trên Pi Zero: https://taoofmac.com/space/blog/2020/09/02/1900#resurrecting
GIF là output thời gian thực
Nhưng việc có load được driver camera và Wi‑Fi cần cho dự án trong bài gốc hay không lại là chuyện khác
Cá nhân mình thấy thời gian boot của các bản phân phối Linux nói chung khá đáng thất vọng, và trên phần cứng yếu như thế này vấn đề còn lớn hơn nhiều
Mình cũng từng làm tối ưu tương tự trên SBC MQ-Pro. Trên laptop cũng cảm nhận khá rõ điều này. MacBook có thể là ngoại lệ, nhưng dù sao đây vẫn là điểm gây khó chịu
Sau khi đã bật, chỉ đăng nhập lại thì gần như tức thì, nhưng reboot thì mất khá nhiều thời gian
Tuy nhiên các distro, vì những lý do hợp lý, tạo kernel và initramfs rất tổng quát, và tổ hợp này không đặc biệt nhanh khi boot
[0]: https://blog.davidv.dev/posts/minimizing-linux-boot-times/
Trừ khi có cấu hình sai tệ hại kiểu NetworkManager chờ 90 giây cho Wi‑Fi không tồn tại. Máy Linux của mình mất khoảng 4 giây đến graphical.target, phần lớn là do kết nối Wi‑Fi và ntpd, mà về nguyên tắc cả hai đều là tùy chọn
Nếu thật sự muốn boot nhanh, bạn có thể bỏ hết các khả năng cấu hình động như lớp tương thích bootloader, abstraction, initramfs. Nhưng khi đó bạn sẽ bị phụ thuộc vào nhà cung cấp phần cứng, nên không đáng
Ví dụ chiếc MacBook Air 11 chạy Linux của mình hiện màn hình đăng nhập nhanh đến mức gần như không kịp thấy log boot. Theo systemd-analyze thì dưới 4 giây đến graphical target
Mấu chốt có vẻ là hai điểm. Không dùng desktop environment, boot vào text mode rồi khi cần thì chạy startx, hoặc boot vào X bằng login manager nhẹ như lightdm. Không có desktop environment thì số service giảm xuống còn ít hơn nhiều lần, giúp giảm mạnh áp lực I/O trong lúc boot trên phần cứng cũ. Ngay cả khi chạy X, hệ thống sau khi boot vẫn dưới 200MB
Điểm nữa là EFI stub có thể tăng tốc: https://wiki.archlinux.org/title/EFISTUB
Trực giác đầu tiên của tôi là liệu có thể dùng một lõi khác không. Có thật sự cần Linux để chụp ảnh rồi truyền lên đám mây không?
Tôi không phải dân phần cứng, nên tò mò không biết với ngân sách tối thiểu thì có thể hoàn thành việc này như thế nào. Bài viết rất thú vị
Có lẽ chỉ vì hiện trên bàn ăn của tôi đang có hai chiếc ESP32-CAM, nhưng tôi đã tò mò không biết cấu hình ESP32-CAM sẽ so sánh ra sao. Có lẽ nó chỉ ổn với ảnh tối đa 2 megapixel, nhưng thời gian khởi động và mức tiêu thụ điện có lẽ đều thấp hơn gần một bậc độ lớn
Nếu tò mò thì chi tiết ở đây: https://components101.com/modules/esp32-cam-camera-module
Về nguyên tắc có thể làm bare-metal, nhưng để các thiết bị ngoại vi cần thiết hoạt động thì không dễ
Tôi đã thắc mắc vì sao kernel tùy chỉnh lại xuất hiện muộn như vậy. Nếu muốn tối ưu thì chẳng phải thường bắt đầu từ LFS hoặc một distro dựa trên mã nguồn sao? Có vẻ các thiết bị kiểu này cũng không nhất thiết cần cập nhật phần mềm tự động
Tôi cũng tò mò liệu có thể tối ưu EFI/BIOS trên những thiết bị như vậy không. Ít nhất trên desktop Arch Linux bình thường của tôi, phần đó chiếm một phần đáng kể thời gian khởi động
$ systemd-analyzeStartup finished in 10.076s (firmware) + 1.339s (loader) + 1.569s (kernel) + 2.974s (initrd) + 3.894s (userspace) = 19.854sTôi không biết chính xác phần cứng Raspberry Pi, nhưng nhiều SoC nhúng khác có bootloader khá tối giản chạy bằng u-boot và thường rất nhanh. Đặc biệt nếu đặt thời gian chờ nhập liệu của người dùng về 0
Một hệ thống kernel tối thiểu với busybox sẽ đỡ khổ hơn nhiều, và Gentoo cũng không phải lựa chọn tệ
> systemd-analyzeStartup finished in 3.259s (firmware) + 35.127s (loader) + 1.823s (kernel) + 2.927s (userspace) = 43.138s3,5 giây thì ấn tượng, nhưng nếu toàn bộ kịch bản thực sự là cứ vài phút kết nối Wi-Fi để upload ảnh, thì ESP32 hẳn sẽ là lựa chọn tốt hơn nhiều về mức tiêu thụ điện
Trừ khi cần một tính năng cụ thể nào đó của mô-đun camera cho Pi mà camera tương thích ESP32-CAM không có
Có vẻ như họ đang làm quá nhiều việc cho một thứ mà vi điều khiển có thể xử lý gần như không tốn sức