Dữ liệu & CPU/Module 2 — Tổng kết & cheat sheet cách máy chạy
14/23
Bài 14 / 23~12 phútMáy chạy thế nàoMiễn phí lượt xem

Module 2 — Tổng kết & cheat sheet cách máy chạy

Recap Module 2: von Neumann, fetch-decode-execute, register/ALU, assembly và pipeline biên dịch. Cheat sheet, glossary, pitfall và self-assessment để bookmark.

TL;DR: Module 2 bóc 5 tầng cốt lõi giải thích điều gì xảy ra khi bạn chạy ./program: kiến trúc von Neumann đặt nền, vòng fetch-decode-execute lặp hàng tỷ lần mỗi giây, register/ALU thực thi phép tính, assembly là ngôn ngữ trung gian trực tiếp trên phần cứng, và compiler tự động ánh xạ code bậc cao xuống lệnh máy tối ưu. Đây là 1 trang để bookmark.

Đã đi qua những gì

Bài 01 đặt nền với mô hình von Neumann — kiến trúc 4 thành phần (CPU, bộ nhớ chính, bus, I/O) mà John von Neumann thiết kế năm 1945 và mọi máy tính hiện đại đều kế thừa. Ý tưởng cốt lõi là stored-program: lệnh và dữ liệu cùng nằm trong một bộ nhớ thống nhất, giúp máy tính lập trình lại bằng phần mềm thay vì nối lại dây. Von Neumann bottleneck cũng xuất hiện ở đây: CPU và bộ nhớ nói chuyện qua bus duy nhất, nên tốc độ truy cập RAM trở thành điểm nghẽn mà mọi tầng cache đều cố giải quyết.

Bài 02 đào sâu chu kỳ fetch-decode-execute — vòng lặp 3 bước mà CPU thực hiện hàng tỷ lần mỗi giây. Program Counter (PC) giữ địa chỉ lệnh tiếp theo, Instruction Register (IR) chứa lệnh đang chạy, clock đồng bộ toàn bộ CPU theo xung nhịp đều đặn. Trace tay một lệnh cộng số nguyên qua từng giai đoạn là cách duy nhất để "nhìn thấy" vòng lặp này trong đầu.

Bài 03 mổ xẻ bên trong CPU: register nhanh hơn RAM hàng trăm lần vì nằm ngay trên chip cùng ALU, ALU thực hiện phép tính nhị phân và lưu kết quả phụ vào flags (zero, carry, overflow), Control Unit giải mã opcode và điều phối tín hiệu điều khiển. Số lượng register rất hạn chế — đây là lý do compiler phải quản lý register allocation cẩn thận.

Bài 04 là assembly nhập môn — không phải để lập trình assembly, mà để đọc hiểu output của compiler. Opcode là mã lệnh số, mnemonic là cách viết người đọc được (mov, add, cmp, jmp). Vòng for trong C biến thành một cụm lệnh cmp + jne nhảy ngược lên đầu vòng lặp.

Bài 05 ghép lại toàn bộ pipeline biên dịch: preprocessor → compiler → assembler → linker. Compiler sinh assembly từ AST, tối ưu hoá nhiều pass (dead code elimination, constant folding, inlining), rồi assembler chuyển thành object file nhị phân. JIT compiler (Java HotSpot, V8) thêm tầng thú vị: compile lúc runtime dựa trên profile thực tế, kết hợp linh hoạt giữa interpret và native code.

Sơ đồ dưới tóm tắt hành trình 5 bài của Module 2 — từ kiến trúc phần cứng đến lúc code bạn viết thành lệnh máy chạy được:

flowchart LR
  A["von Neumann<br/>CPU+RAM+bus"] --> B["Fetch-Decode-Execute<br/>PC, IR, clock"]
  B --> C["Register + ALU<br/>noi tinh toan"]
  C --> D["Assembly<br/>mov/add/cmp/jmp"]
  D --> E["Compiler<br/>code -> lenh may"]

Cheat sheet

Khái niệmÝ chínhGhi nhớ
Von NeumannCPU + bộ nhớ + bus + I/O; lệnh và dữ liệu cùng 1 bộ nhớStored-program = lập trình lại bằng phần mềm, không nối lại dây
Stored-programLệnh là dữ liệu — nằm trong RAM, CPU fetch và decode như đọc sốCho phép OS tải bất kỳ chương trình nào vào RAM và chạy
Von Neumann bottleneckCPU và RAM nói chuyện qua 1 bus — fetch lệnh tranh băng thông với đọc dữ liệuCache L1/L2/L3 là giải pháp chính; Module 3 đào sâu thêm
Program Counter (PC)Register giữ địa chỉ lệnh tiếp theo sẽ fetchTự tăng sau mỗi fetch; lệnh jmp ghi đè trực tiếp
Instruction Register (IR)Register giữ lệnh đang decode/executeSau fetch, nội dung từ bộ nhớ vào IR, rồi Control Unit giải mã
Fetch-decode-execute3 bước lặp: đọc lệnh từ PC, giải mã opcode, thực thiMỗi vòng = 1 lệnh (đơn giản); pipeline CPU chồng lấp nhiều vòng
ALUMạch số học-logic: cộng/trừ/AND/OR/shift; kết quả phụ vào flagsKhông nhớ trạng thái giữa 2 lệnh; Control Unit đọc flags để rẽ nhánh
Flags registerZero (Z), Carry (C), Overflow (V), Sign (N) — kết quả phụ của ALUcmp = sub nhưng bỏ kết quả, chỉ giữ flags; jne đọc Z flag
OpcodeSố nhị phân xác định kiểu lệnh; mnemonic là cách đọc của ngườimov, add, cmp, jmp là mnemonic — CPU thấy byte tương ứng
ISAInstruction Set Architecture: hợp đồng giữa phần mềm và phần cứngx86-64 và ARM64 là 2 ISA phổ biến nhất hiện nay
Compile pipelinePreprocessing → AST → IR → optimize → assembly → object → link-O2 kích hoạt hàng chục pass tối ưu; godbolt.org để quan sát
JITJust-In-Time: compile lúc runtime từ bytecode/IR thành native codeHotSpot compile "hot method" sau ngưỡng lời gọi (mặc định 10 000)

Glossary

Thuật ngữĐịnh nghĩa 1 câu
von Neumann architectureKiến trúc máy tính với CPU, bộ nhớ chính, bus và I/O — lệnh và dữ liệu cùng nằm trong một không gian địa chỉ thống nhất.
stored-programNguyên tắc thiết kế: lệnh là dữ liệu, nằm trong bộ nhớ, có thể thay đổi mà không cần thay đổi phần cứng.
busĐường truyền điện chung nối CPU với bộ nhớ và thiết bị I/O; gồm address bus, data bus và control bus.
von Neumann bottleneckĐiểm nghẽn khi CPU và bộ nhớ dùng chung bus — fetch lệnh và đọc dữ liệu tranh băng thông, CPU phải chờ RAM.
program counter (PC)Register đặc biệt giữ địa chỉ bộ nhớ của lệnh tiếp theo sẽ được fetch; tự tăng sau mỗi fetch hoặc bị ghi đè bởi lệnh nhảy.
instruction register (IR)Register giữ lệnh đang được decode và thực thi; nội dung được chép từ bộ nhớ vào IR trong giai đoạn fetch.
fetch-decode-execute cycleVòng lặp 3 bước CPU thực hiện liên tục: fetch lệnh từ địa chỉ PC, decode opcode, execute.
clock cycleĐơn vị thời gian cơ bản của CPU — 1 nhịp xung; CPU 3 GHz thực hiện 3 tỷ xung mỗi giây.
registerÔ nhớ cực nhanh nằm trực tiếp trên chip CPU, dung lượng nhỏ (hàng chục đến vài trăm byte), latency dưới 1 ns.
ALUArithmetic Logic Unit — mạch thực hiện phép toán số học (cộng, trừ) và logic (AND, OR, NOT, shift) trên số nguyên.
control unitThành phần CPU giải mã opcode và phát tín hiệu điều khiển cho các khối khác (ALU, register file, bộ nhớ).
flags registerRegister giữ bit trạng thái sau mỗi lệnh ALU: Zero (kết quả bằng 0), Carry (tràn không dấu), Overflow (tràn có dấu), Sign.
opcodePhần số nguyên nhị phân trong lệnh máy xác định kiểu phép toán; mnemonic là cách người đọc viết tắt.
ISAInstruction Set Architecture — tập lệnh và quy ước là hợp đồng giữa phần mềm và phần cứng; x86-64 và ARM64 là hai ISA chính.
JIT compilerJust-In-Time: compiler chạy lúc runtime, profile code thực tế rồi compile phần "nóng" thành native code để tăng tốc.

Pitfall tổng hợp

Pitfall 1: Đếm dòng code để ước tính tốc độ

Số dòng source code không phản ánh số lệnh máy, và số lệnh máy không phản ánh thời gian chạy.

// "Vong lap ngan hon phai nhanh hon" -- SAI
for (int i = 0; i < 4; i++) arr[i] *= 2;   // 4 lan nhan

// Compiler co the sinh ra 1 lenh SIMD xu ly 4 phan tu cung luc
// Hoac inlining bien 4 vong lap thanh 4 lenh noi tiep -- nhanh hon
// Cach do dung: benchmark thuc te hoac xem assembly -O2
// Time cua CPU phu thuoc cache miss, branch prediction, IPC -- khong phu thuoc dong code

Pitfall 2: Tối ưu tay thay vì để compiler làm

Compiler hiện đại (GCC, Clang, javac + HotSpot) tối ưu tốt hơn tay trong phần lớn trường hợp với -O2/-O3.

// "Toi tu nhan bang shift cho nhanh" -- thuong vo ich
int x = n << 3;   // thay vi n * 8

// Compiler tu dong nhan ra n * 8 == n << 3 va sinh shift
// Viet n * 8 ro rang hon, compiler khong cham hon
// Thay vao do: do profile truoc, tim hotspot, roi moi toi uu dung cho
// Premature optimization la nguon goc cua moi toi te -- D. Knuth

Pitfall 3: Quên bật -O2 hoặc -O3 khi build production

Debug build (-O0) tắt mọi tối ưu để giữ thứ tự lệnh khớp source — chậm hơn production build tới 5–10x.

# SAI -- build production ma de mac dinh -O0
gcc main.c -o app

# DUNG -- production nen dung -O2 it nhat
gcc -O2 main.c -o app

# Java: HotSpot tu dong JIT; khong co flag -O tuong duong
# nhung chay du lau de HotSpot warmup la can thiet khi benchmark

Pitfall 4: Nhầm truy cập bộ nhớ rẻ như phép tính ALU

ALU hoàn thành phép cộng trong 1 clock cycle. Đọc RAM mất hàng trăm cycle. Cache L1 hit mất khoảng 4 cycle, L2 khoảng 12 cycle, L3 khoảng 40 cycle, RAM khoảng 200 cycle.

// Chuong trinh A: duyet mang tuyen tinh -- cache-friendly
for (int i = 0; i < N; i++) sum += arr[i];

// Chuong trinh B: truy cap ngau nhien -- cache miss cao
for (int i = 0; i < N; i++) sum += arr[rand_index[i]];

// B co the cham hon A 10-50x du so lenh CPU giong nhau
// Ly do: B lien tuc gap cache miss, CPU phai doi RAM

Pitfall 5: Nhầm bytecode Java là lệnh máy

Bytecode Java (.class file) là lệnh cho JVM — một máy ảo stack-based. Không phải lệnh x86-64 hay ARM64. CPU không đọc bytecode trực tiếp.

Source (.java)
   |-- javac --> Bytecode (.class)  [JVM instruction set]
                    |-- JIT (HotSpot) --> Native code  [x86-64 / ARM64]
                                              |-- CPU executes

Khi benchmark Java, phải để HotSpot warmup (chạy qua code ít nhất vài nghìn lần) trước khi đo — không thì đang đo thời gian interpret, không phải native code.

Pitfall 6: Nghĩ compiler luôn sinh assembly "giống" code gốc

Với -O2, compiler được phép sắp xếp lại lệnh, xoá biến không dùng, inline hàm, và thậm chí tính compile-time kết quả mà bạn nghĩ sẽ tính lúc runtime.

// Source:
int square(int n) { return n * n; }
int result = square(5);  // goi ham

// Assembly -O2 co the tra truc tiep:
// mov eax, 25   -- compiler da tinh 5*5 = 25 tai compile time (constant folding)
// Khong co call square gi ca

Dùng godbolt.org để quan sát assembly thực tế với từng flag tối ưu.

Self-assessment

Bạn đã đạt Module 2 nếu trả lời được:

  • Explain được mô hình von Neumann: vai trò CPU, bộ nhớ chính, bus và I/O, và lý do stored-program là ý tưởng then chốt — nếu chưa chắc, đọc lại bài 01 section "Mô hình 4 thành phần" + "Stored-program".
  • Trace được chu kỳ fetch-decode-execute của một lệnh cụ thể: PC trỏ đâu, IR chứa gì, ALU tính toán thế nào, PC tăng hoặc nhảy ra sao — nếu chưa chắc, đọc lại bài 02 section "Ba bước lặp" + bảng trace tay.
  • Explain được vai trò register, ALU và control unit, và lý do register nhanh hơn RAM — nếu chưa chắc, đọc lại bài 03 section "Register" + "ALU và flags".
  • Đọc được assembly cơ bản của một ISA đơn giản: nhận ra mov, add, cmp, jmp và hiểu chúng làm gì — nếu chưa chắc, đọc lại bài 04 section "Mnemonic phổ biến".
  • Ánh xạ được một đoạn code bậc cao (vòng for, câu if) xuống các lệnh máy tương ứng và giải thích từng bước — nếu chưa chắc, đọc lại bài 05 section "Từ vòng for tới cmp + jne".

What's next

Bạn vừa hiểu CPU chạy thế nào ở mức cơ bản — von Neumann, fetch-decode-execute, register, assembly, compile pipeline. Câu hỏi tiếp theo tự nhiên là: CPU hiện đại làm thế nào để nhanh hơn hàng trăm lần so với mô hình 3 bước đơn giản?

Module 3 "CPU hiện đại" sẽ mở nắp pipeline thực sự: instruction pipelining chồng lấp nhiều lệnh, branch prediction đoán trước lệnh nhảy, out-of-order execution sắp xếp lại lệnh để tránh stall, và cách đo hiệu năng thực tế bằng perf thay vì đếm dòng code.

CPU hiện đại

Tài liệu mở rộng

📚 Sách nền tảng
  • Code: The Hidden Language of Computer Hardware and Software — Charles Petzold. Xây từ công tắc điện lên máy tính hoàn chỉnh, giải thích ALU, thanh ghi và fetch-execute cycle theo cách trực quan nhất. Không cần nền toán — chỉ cần tò mò.
  • Computer Organization and Design — Patterson & Hennessy (RISC-V edition). Giáo trình kinh điển CS61C (UC Berkeley) — mổ xẻ datapath, pipeline, cache và memory hierarchy với độ sâu kỹ thuật đầy đủ. Đọc sau khi đã xong Module 3.
📚 Công cụ thực hành
  • godbolt.org — Compiler Explorer: Dán code C/C++/Rust/Java, chọn compiler và flag, thấy ngay assembly tương ứng. Bật -O2 rồi thử xoá một biến, thêm const, đổi vòng lặp — quan sát assembly thay đổi thế nào. Cách tốt nhất để liên kết bài 04-05 với thực tế.

Bài tiếp theo: CPU hiện đại — tổng quan

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên