Lần đầu học online

Hôm nay viết mail xin nghỉ việc ở FPT Japan, chuẩn bị kết thúc sau 9 năm gắn bó.
Vậy đã 9 năm, kinh nghiệm chỉ gói gọn trong vài ba chữ, embedded, c/c++, video coding, linux driver. 9 năm làm có từng đó, nói ra lại tưởng là cỡ chuyên gia nhưng hóa ra không phải, cái nào cũng lõm bõm.

Tốt nghiệp kĩ sư điện, nên cơ bản kinh nghiệm coding đều học hỏi trong quá trình làm việc, thành ra nhận được kiến thức kiểu làm nhiều thì quen tay hơn là dùng não, nhìn đến cái nào cũng thấy cái nền móng thiêu thiếu cái gì đấy.

Ờ, thôi biết vậy, thiếu nhưng biết bù thì không sao, khóa học online giờ rất rất nhiều, cứ muốn là học được, chỉ là có chịu học hay không mới là vấn đề thôi.

Thử bắt đầu bằng khóa này xem, thấy kha khá các expert gợi ý.
https://see.stanford.edu/Course/CS107/
Song song đọc quyển “programming perspective“, là giáo trình của course trên.

Có 27 bài giảng, nếu cứ đều đều 1 ngày 1 bài hết 27 ngày.
Có tài liệu & bài tập … thong thả tính 2 ngày để làm.
Vậy có 3 ngày/1 bài → 3 tháng.
Nếu bắt đầu học từ giờ 21/06 thì đến 21/08 là xong.
Thử bắt đầu thật nghiêm túc 1 khóa học online xem thế nào vậy!

Từ khóa register trong C

Trong lập trình nhúng (embedded programming), thi thoảng hay bắt gặp từ khóa register, thường là những chỗ tính toán loằng ngoằng, bit biếc dịch ngược dịch xuôi. Register được dùng đặt trước kiểu dữ liệu khi khai báo biến. Tác dụng của từ khóa register, nói một cách ngắn gọn là làm tăng hiệu năng(performance) của chương trình.

Thêm cái của nợ này vào thì tại sao có thể tăng được hiệu năng?. Mà thực sự tăng thật thì tăng được bao nhiêu?
Để thêm phần sinh động, thử một ví dụ nhỏ dưới xem nó có ra cái gì không?

void main()
{
clock_t start, end;
double t;
int i; // không dùng register
//register int i; // sử dụng register
start = clock();
while(i < 0xFFFFFFFF) i++;
end = clock();

t = ((double) (end – start)) / CLOCKS_PER_SEC;
printf("time used %f\n",t);
}

Biên dịch với gcc version 6.3.0
Chạy trên Raspberry Pi 2B (ARMv7 Processor rev 5 (v7l)).
– Sử dụng từ khóa register: time used 9.583080 giây
– Không sử dụng từ khóa register: time used 38.256520 giây

Ví dụ trên cho thấy dùng từ khóa register, thì hiệu năng nó tăng thật, riêng trong trường hợp này thì cũng đang kể đấy chứ nhỉ :-).Tất nhiên cải thiện được bao nhiêu thì phải tùy vào hoàn cảnh cụ thể khi sử dụng, mức độ sử dụng biến đó … Nhưng mà ngon lành vậy thì toàn bộ khai báo biến trong chương trình cứ mặc định thêm luôn từ khóa này thì chuyện gì xẩy ra?.
Để hiểu được điều đó thì trước hết thử xem tại sao hiệu năng nó tăng?
Quay lại với vấn đề cơ bản hơn một chút, trong kiến trúc của vi xử lý thì ALU (Arithmetic Logic Unit) là con trâu đóng vai trò xử lý các tính toán số học. Dữ liệu đưa vào làm việc với ALU phải chứa trong một vùng đặc biệt, gọi là các thanh ghi(register), và ALU chỉ làm việc với đống thanh ghi đó. Trong khi đó các biến khai báo trong chương trình thì đặt ở bộ nhớ ngoài (RAM chẳng hạn …). Do đó với khai báo biến thông thường, để thực hiện một phép tính thì cần có 3 bước.
① Nạp giá trị từ vùng nhớ chứa biến vào register
➁ Yêu cầu ALU xử lý register vừa được nạp giá trị.
③ Đưa kết quả vừa xử lý của ALU ra ngoài vùng nhớ chứa biến.
Hình dung thô thiển như hình vẽ dưới đây.

alu

Khi thêm từ khóa register để khai báo biến, thì tức là ta đã yêu cầu trình biên dịch ưu tiên đặc biệt dành luôn vùng register để chứa biến đó. Và hiển nhiên khi thực hiện tính toán trên biến đó thì giảm được bước ①&③, giảm bớt thủ tục thì hiệu năng nó tăng lên là chuyện dễ hiểu :-).
Quay lại với ví dụ trên, để đảm bảo đúng như thánh phán, thử thêm option “-save-temps” để lấy tập mã lệnh assembly xem nó có thật vậy không.

gcc register.c -o test -save-temps

Đoạn mã assembly ở dưới tương ứng với vòng while loop ở ví dụ trên. Dễ thấy chỗ bôi màu đó khi không dùng từ khóa register tương ứng với bước ①&③ ở trên. Còn khi dùng từ khóa register thì trình biên dịch nó dùng luôn thanh ghi r4 cho việc chứa biến i.
p/s: Nếu không dễ thấy thì tự tra cứu lại lệnh assembly của ARM

Không sử dụng từ khóa register

ldr r3, [fp, #-8] // bước ①
add r3, r3, #1
str r3, [fp, #-8] // bước ③
.L2:
ldr r3, [fp, #-8]
cmn r3, #1
bne .L3

Sử dụng từ khóa register

.L3:
add r4, r4, #1
.L2:
cmn r4, #1
bne .L3

Đến đây, ta thấy rõ ràng khi dùng từ khóa register, thì thay vì dùng bộ nhớ ngoài đển lưu biến thì chương trình sẽ sử dụng luôn register để lưu biến đó. Cái gì ngon, quí thì dĩ nhiên hiếm, register cũng thấy, số lượng register rất nhỏ so với bộ nhớ ngoài, mà đây còn là tài nguyên dùng chung. Do đó không thể chơi kiểu vô tổ chức để thằng nào thích lấy làm đồ riêng thì lấy được. Tùy từng tình huống, yêu cầu để lựa chọn phần xử lý nào nên sử dụng register để tăng hiệu năng mà có thể chấp nhận cho nó xin một vài register về làm của riêng.
Nếu không tin thì thử thêm đoạn code này “register int k[100*1024*1024];” vào
để chiếm register xem chương trình xem nó có ngỏm không ^.^

Zero start with video coding

Hoàn cảnh éo le.
Ra trường giữa 2009, tham gia 1 dự án làm về DTV (Digital Television) đến tận đầu 2012, vậy là 2 năm rưỡi, biết được một chút về video decoding do đàn anh  chỉ dạy cho lúc bắt đầu dự án, còn lại OT vật vã cho kịp deadline. Sau này ngẫm lại thấy đa phần kiến thức cơ bản về video coding bị sai → quá nguy hiểm.
Vào 7/2013 sang Nhật làm việc đến 4/2017 trong dòng dự án về 4k – Television và Camera recorder. Trong thời gian đó có tầm 1 năm rưỡi cuối làm về video encoding. Về công việc thì test nhiều hơn là code. Do  rảnh rỗi không biết làm gì, nên học thêm chút về video encoding cho qua ngày.
Rút ra được vài ba kinh nghiệm quí báu, khi làm việc trong cái mảng việc này (mảng khác chắc cũng thế).
– ① Nên theo từ lúc đang đi học, như thế sẽ được chỉ dạy kiến thức cơ bản bởi những người biết về kiến thức cơ bản.
– ➁ Nếu ko có cơ hội ①, khi vào dự án chiến luôn mà nghe trong team chém gió (sợ nhất là các thánh phán), phải điều tra cẩn thận trước khi coi đó là chân lý.
– ③ Cái số ➁ cực kì nguy hiểm, nếu không may mắn có cái ① thì nên tìm sư huynh cho thật ngon mà học, vừa nhanh vừa an toàn.
Mình là nạn nhân con số ➁, sau nhiều năm mới sửa sai được một số vấn đề cơ bản, mà suýt bị nó làm cho tẩu hỏa nhập ma. Ngoài ra công việc gián đoạn không làm video coding nữa, nên giờ ngồi viết lại, lỡ sau này may mắn có cơ hội làm tiếp về video coding thì có chỗ mà tra cứu cho nhanh :-).

Một vài điểm bắt đầu.
Có mail hỏi 1 ông anh, chuyên gia video coding ở Đức, thì đại ka gợi ý đọc quyển này. Mình nhai mãi chưa xong (vẫn tiếp tục nhai khi có thời gian), toàn kiến thức nền tảng, phù hợp cho ai thích đi theo hướng nghiên cứu. Còn giờ đang cần tiếp cận theo hướng ứng dụng.
Bắt đầu một vài gạch đầu dòng cơ bản.
– Video thực ra là một chuỗi ảnh(picture) sắp xếp liên tục theo thời gian (có lẽ ai cũng biết?), vì vậy nén video chẳng qua là nén lần lượt các ảnh này.
– Nén video cơ bản là nén mất dữ liệu (lossly), nhưng bất kì chuẩn nén video nào cũng chứa 2 giai đoạn. Giai đoạn 1 nén lossly (transform + quantization) và giai đoạn 2 nén lossless (entropy coding). Một số chuẩn nén như AVC/H.264, HEVC/H.265… cho phép chỉ nén lossless bằng cách cho phép bỏ quá trình nén lossly.
– Xét ở đặc điểm sau khi nén của picture, có thể chia thành 2 loại kỹ thuật nén là INTRA (nén trong ảnh) & INTER (nén liên ảnh). INTRA là cách nén picture chỉ dựa vào thông tin chứa trong bản thân picture đó, ngược lại INTER có sử dụng thông tin các picture lân cận để thực hiện nén picture đó.
– Quá trình nén picture được thực hiện theo từng block có kích thước vuông giống nhau. Đối với chuẩn nén H.264 trở về trước gọi là Macroblock kích thước 16×16 pixel, còn đối với H.265 gọi là Coding Tree Unit và nó cho phép chọn từ 16×16 ~ 64×64 pixel. Với các chuẩn nén không phải của ISO or ITU-T, ví dụ VP8, VP9 của google, tên gọi các block đó có thể khác nhưng cơ bản đều mang ý nghĩa giống nhau.

Sẽ có rất nhiều thắc mắc, ví dụ INTRA & INTER được thực thi cụ thể thế nào? nó thể hiện thế nào trong quá trình xử lý các block trong từng picture?, google phát toàn ra 1 đống như motion vector nó nằm ở đâu trong khái niệm trên? vân vân và vân vân. Với một cơ số khái niệm, cùng với đống tài liệu trên mạng (rác cũng nhiều), vội vàng dễ bị chết đuối cho nên đừng vội tham lam, đi từ từ rồi sẽ đến.
P/S: Kiến thức mình chia sẻ thuộc trường hợp số ➁, cẩn thận khi có ý định sử dụng nhé!