Bit field in C.

Trong lập trình C, khi define các trường của struct, chúng ta có thể chỉ định số bit dùng để lưu trữ trường dữ liệu đó.

Với cách define ban đầu, size của struct sẽ là 7 byte.

Bây giờ nếu chúng ta nhìn kỹ lại, chẳng hạn để lưu trữ True hoặc False cho biến boolean, thực ra 1 bit là đủ. vậy tại sao ta phải dùng đến 8 bit để lưu. Thêm nữa, nếu như ta xác định giá trị tối đa mà chúng ta lưu và biến uint16_t int2 không vượt qua 1024, vậy thì sử dụng 10 bit là đủ, không cần đến 16 bit của kiểu uint16_t để lưu.

Với cách define struct theo kiểu thứ 2, size của struct sẽ là 4 byte, như vậy chúng ta đã tiết kiệm được ~40% memory.

Quay lại về vấn đề gặp phải trong dự án của mình, dữ liệu giữa module trong kernel-space và user-space được truyền qua lại thông qua thanh ghi. Truyền dữ liệu qua thanh ghi có tốc độ chậm hơn nhiều so với Ram, nên nếu kích thước dữ liệu giảm đi bao nhiêu thì thời gian truyền sẽ được giảm đi bấy nhiêu. Bằng cách định nghĩa lại struct dữ liệu theo kiểu trên, mình đã giảm được 70% kích thước dữ liệu, đồng nghĩa tốc độ truyền được tăng lên gấp 3.

Với thiết kế truyền dữ liệu theo kiểu sử dụng struct như thế này thì tốt nhất là phần code define struct phải giống y hệt nhau giữa kernel và user-space. Tuy nhiên trong dự án của bọn mình, vì lý do khách quan nên phần define giữa 2 tầng không giống hệt nhau được. Bọn mình đã xử lý bằng cách tạo ra 1 bảng bitmap của từng trường trong struct. Nhờ vậy mình có thể chuyển dữ liệu qua lại giữa 2 struct của kernel và user-space mặc cho cách define các trường bên trong có sự khác nhau. Nếu như code của struct thay đổi thì bảng bitmap kia cũng phải cập nhật lại bằng tay.

Sau 1 vài năm hoạt động thuận lợi không xảy ra lỗi lầm gì thì tự nhiên đợt này lại xuất hiện bug. Và nguyên nhân của bug là do bảng bitmap không mapping đúng với code hiện tại.

Khi đó mình đã debug như thế nào?

Cách debug cũng rất đơn giản, đó là ngồi tính toán lại từng trường trong struct để tìm ra bit nào bị lệch, từ đó có cập nhật lại bảng bitmap cho đúng. Kích thước của struct khoảng 400 bytes ~ 2000 bits. Trung bình 1 ngày mình tính toán lại được khoảng 500 bits, vậy là sau 4 ngày mình đã tính lại được cả struct.
Tuy nhiên vẫn không tìm ra được bug ở đâu. Đến đây thì mình đoán là do 2 trường hợp:

  • Trường hợp 1: mình tính toán bitmap bị sai
  • Trường hợp 2: khi build code ở tầng kernel và user-space, gcc chạy với các option khác nhau, có thể gây ra sự sai lệch trong struct alignment

Đối với struct alignment thì gcc có thể chèn thêm bit phụ vào cho 1 trường nào đấy trong struct để cho thành đủ byte.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top