2 điểm bởi GN⁺ 2025-10-05 | 1 bình luận | Chia sẻ qua WhatsApp
  • Việc phát hành Zig 0.15.1 đã cải thiện đáng kể tốc độ biên dịch so với phiên bản trước
  • Kết quả đo thời gian build thực tế trong dự án Ghostty cho thấy thời gian chạy tổng thể đã được rút ngắn
  • Dù vẫn còn sử dụng LLVM ở một phần, nhưng khi áp dụng backend riêng, kỳ vọng cải thiện tốc độ thêm nữa là rất lớn
  • Biên dịch tăng dần (incremental compilation) vẫn chưa được triển khai hoàn chỉnh, nhưng lợi ích hiệu năng đã xuất hiện ngay cả trong các bản build từng phần
  • Trong tương lai, khả năng cao sẽ hiện thực hóa được môi trường build nhanh hơn nữa cùng trải nghiệm phát triển tốt hơn

Tổng quan

Bắt đầu từ phát biểu của Andrew Kelley rằng "trình biên dịch quá chậm nên sinh ra lỗi", Zig trong nhiều năm qua đã theo đuổi nhiều cải tiến về cấu trúc với mục tiêu rút ngắn thời gian biên dịch

  • Nhóm Zig đã nỗ lực loại bỏ LLVM, phát triển backend sinh mã riêng, xây dựng linker riêng, và cuối cùng là hiện thực hóa biên dịch tăng dần
  • Thành quả của quá trình phát triển dài hạn này bắt đầu thể hiện rõ ở phiên bản Zig 0.15.1, và sự thay đổi về thời gian build đã được đo đạc, chia sẻ trên dự án thực tế (Ghostty)

Tốc độ biên dịch Build Script

  • Zig 0.14: 7 giây 167ms
  • Zig 0.15: 1 giây 702ms

Đây là thời gian build của chính script build.zig, và là chi phí ban đầu phải trả mỗi lần trong môi trường build mã nguồn mới

  • Tần suất biên dịch lại build script được giữ ở mức thấp, nhưng nó ảnh hưởng trực tiếp đến trải nghiệm người dùng khi lần đầu tự build dự án

Build toàn bộ binary không dùng cache (Ghostty)

  • Zig 0.14: 41 giây
  • Zig 0.15: 32 giây

Đây là tổng thời gian build binary, bao gồm cả thời gian build script build

  • Với Zig 0.15, còn có thêm hiệu quả cải thiện tốc độ khoảng 2 giây, và sự khác biệt ban đầu cũng rất rõ ràng theo thời gian thực tế
  • Hiện tại backend x86_64 riêng vẫn chưa được tận dụng hoàn toàn, và phần lớn vẫn tiếp tục dùng LLVM
  • Trong tương lai, khi Ghostty được build hoàn toàn bằng backend riêng, thời gian được dự đoán có thể giảm xuống dưới 25 giây (chỉ còn khoảng một nửa so với trước)

Build tăng dần (file thực thi Ghostty)

  • Zig 0.14: 19 giây
  • Zig 0.15: 16 giây

Đây là thời gian cần để build lại sau một thay đổi một dòng có ý nghĩa (thêm lệnh gọi log trong mã giả lập terminal)

  • Đây là bản build từng phần trong tình huống build script và đồ thị phụ thuộc đã ở trạng thái cache
  • tính năng biên dịch tăng dần vẫn chưa được triển khai hoàn hảo, cải thiện hiệu năng đã thể hiện rất rõ
  • Nếu loại trừ LLVM đang được sử dụng, còn có khả năng rút xuống khoảng 12 giây
  • Khi build tăng dần thực thụ được triển khai trong tương lai, thậm chí có thể kỳ vọng build ở mức mili giây

Build tăng dần (libghostty-vt)

  • Zig 0.14: 2 giây 884ms
  • Zig 0.15: 975ms

Đây là phép đo thời gian chỉ build lại một phần libghostty-vt sau thay đổi một dòng

  • libghostty-vt có thể được build hoàn toàn bằng backend x86_64 riêng, nên các cải tiến của Zig được phản ánh trực tiếp mà không bị ảnh hưởng bởi LLVM
  • Ngay cả khi chưa có biên dịch tăng dần, đạt thời gian build dưới 1 giây vẫn là một bước tiến đáng kể
  • Hiệu quả được nâng cao trong quy trình làm việc của lập trình viên nhờ trải nghiệm phản hồi gần như tức thì
  • Các backend x86_64 và aarch64 đang dần ổn định hơn, và có khả năng sẽ được áp dụng cho toàn bộ Ghostty trong vài tháng tới

Hiện trạng cải thiện tốc độ build

  • Bản build Ghostty dùng Zig 0.15.1 hiện đã nhanh hơn rõ rệt ở mọi hạng mục đo đạc
  • Dù backend riêng và biên dịch tăng dần vẫn chưa hoàn thiện, riêng những kết quả hiện tại cũng đã đủ ấn tượng
  • Trong 1–2 năm tới, có thể kỳ vọng các kết quả cải thiện tốc độ còn đột phá hơn nữa
  • Có thể cảm nhận rõ rằng việc chọn Zig là một lựa chọn hợp lý từ góc độ tốc độ build

1 bình luận

 
GN⁺ 2025-10-05
Ý kiến Hacker News
  • Khi tốt nghiệp trung học năm 1995, tôi từng biên dịch lại "Borland Pascal version Turbo Vision for DOS" trên Intel 486, và giờ lại được trải nghiệm tốc độ biên dịch nhanh đến mức tương đương như vậy
    Turbo Vision là một framework cửa sổ TUI, được dùng để phát triển IDE Borland Pascal và C++
    Có thể xem nó như một chế độ ký tự triển khai IDE của JetBrains trong 10MB thay vì 1000MB
    Wikipedia về Turbo Vision

  • LLVM là một kiểu cái bẫy
    Khởi động bootstrap thì rất nhanh và gần như được miễn phí đủ loại optimization pass cùng hỗ trợ đa nền tảng, nhưng lại đánh mất khả năng tinh chỉnh hiệu năng ở giai đoạn tối ưu cuối hoặc giai đoạn linking
    Tôi nghĩ Cranelift sắp được bật trong Rust
    Nhưng cũng chính vì Rust ban đầu chọn LLVM nên mới có được vị thế hiện nay
    Go từ sớm đã quyết định tự quản lý code generation và link thay vì giao ra bên ngoài, và đang hưởng lợi rất nhiều từ lựa chọn đó

    • Tôi khó đồng ý với lập luận rằng LLVM là cái bẫy, và Rust lại chính là ví dụ tốt
      Thực tế phần tạo mã bằng LLVM chỉ chiếm một phần rất nhỏ trong compiler, và nếu muốn thay thế thì có thể đổi sang codegen_cranelift hay codegen_gcc
      Việc phụ thuộc vào SIMD vendor intrinsic đúng là một vấn đề "lock-in", nhưng đây là vấn đề thuộc về cấu trúc ngôn ngữ
      Với đa số ngôn ngữ, bắt đầu bằng backend LLVM là lựa chọn hợp lý
      Với các ngôn ngữ tương tự C/C++, chỉ cần pipeline mặc định của LLVM cũng tối ưu khá tốt, còn ngôn ngữ có đặc điểm khác thì sẽ tự viết pipeline tối ưu riêng
      Các trường hợp như Go, vốn đã tích hợp backend riêng ngay từ đầu, đúng là trông có vẻ thành công, nhưng đó không hẳn là yếu tố khác biệt đặc biệt, và việc tự triển khai đi kèm chi phí cơ hội khá lớn

    • Compiler của Go và Ocaml thực sự rất nhanh
      Họ đã xây dựng thư viện riêng tử tế ngay từ đầu, và giờ không còn lý do gì phải chịu thiệt về tốc độ
      Tôi không muốn làm việc trong môi trường mà mỗi lần compile mất hơn 1 phút
      Tôi ước mỗi dự án có một compiler riêng cho môi trường dev, rồi chỉ dùng thứ nặng như llvm cho bản build cuối cùng

    • Nếu một ngôn ngữ dựa trên LLVM mà nhắm tới việc thay thế C++, thì rốt cuộc nó vẫn sẽ phụ thuộc vào C++
      Ngôn ngữ phải có khả năng bootstrap bằng chính nó
      Ban đầu có thể dùng các công cụ tiện lợi, nhưng chúng chỉ là cách tiết kiệm thời gian chứ không phải thứ bắt buộc
      Tôi hoàn toàn đồng cảm với lựa chọn mà đội ngũ Go đã đưa ra

    • Tôi mong Cranelift tiếp tục phát triển bền vững
      LLVM hiện nay bị phân nhánh tràn lan theo từng hãng CPU, mỗi nhánh lại gói các cải tiến riêng cho từng CPU trong các package đóng
      Nếu dùng frontend của ngôn ngữ khác hoặc gặp bug compiler thì tình hình sẽ cực kỳ gian nan

    • Có người đặt câu hỏi rằng ngôn ngữ có thể tự do chuyển sang backend khác, vậy sao lại có thể gọi đó là cái bẫy?

  • Nếu tốc độ compile cản trở việc phát triển, thì tại sao không làm interpreter?
    Tốc độ chạy và tốc độ compile về bản chất là độc lập với nhau
    Nếu dùng interpreter thì cũng dễ làm thêm các công cụ phát triển như instrument code hay điều khiển runtime
    Có một số rất ít trường hợp phải debug đúng binary RELEASE đã tối ưu, nhưng trong đa số tình huống thì interpreter hoặc bản build DEBUG là đủ

    • Tôi nghe nói Rust được xếp theo thứ tự an toàn, hiệu năng, tính tiện dụng; còn Zig là hiệu năng, tính tiện dụng, an toàn
      Từ góc nhìn đó, việc cải thiện tốc độ build là điều thuyết phục, nhưng interpreter lại là lựa chọn phù hợp hơn khi ưu tiên hàng đầu là tính tiện dụng

    • Tôi thích cách tiếp cận của Julia
      Trong môi trường tương tác đầy đủ, interpreter thực chất biên dịch mã rồi chạy ngay lập tức
      Các môi trường Common Lisp như SBCL cũng tương tự

    • Nếu nhìn ở cực đoan thì tốc độ chạy và tốc độ compile là độc lập
      Giữa hai đầu đó có một "vùng có thể thỏa hiệp", nơi có thể làm compiler nhanh hơn mà không làm giảm hiệu năng của file thực thi

    • Có người cho rằng lĩnh vực game không phải là trường hợp đặc biệt

  • Tốc độ compiler tốt nhất từ trước đến nay với tôi là TCC (tác phẩm của Fabrice Bellard)
    Nó áp đảo về tốc độ dù không có multithread hay tối ưu phức tạp
    Tôi dùng Clang cho bản release, nhưng hiệu năng code generation của TCC cũng không tệ

    • Tôi nghĩ Delphi còn biểu đạt tốt hơn, an toàn hơn, mà tốc độ compile vẫn rất nhanh

    • Compiler của Go cũng khá nhanh

    • Tôi từng nghĩ DMD là "tiêu chuẩn vàng" vì có thể compile cả C lẫn D mà vẫn nhanh

    • Tôi hy vọng TCC sẽ hỗ trợ C23

    • Không có thứ gì là "tiêu chuẩn vàng" duy nhất
      vlang cũng nhanh đến mức chỉ mất vài giây để biên dịch lại, và compiler của Go cũng cực nhanh
      Ngoài ra còn có các kỹ thuật như build caching để tránh phải biên dịch lại ngay từ đầu, nên đây không phải đặc quyền của riêng ai

  • Khi build app bằng zig, tôi rất hài lòng với incremental build
    Có thể build một static binary duy nhất dùng nhiều thư viện như SQLite, luau nhanh gần bằng Go
    Tuy vậy, compiler self-hosted hiện vẫn còn khá nhiều bug
    Ví dụ SQLite vẫn phải dùng llvm, có thể xem issue liên quan ở đây

  • Tôi tò mò Zig có thể tích hợp tốt với các hệ thống build như Bazel, Buck2 hay không
    Script build của Zig là Turing-complete, nên tôi lo trong các hệ thống kiểu này việc caching và tự động hóa build sẽ không dễ
    Lý do này cũng giống như việc trong Rust người ta thích thư viện dùng được mà không cần build.rs hơn
    Tôi cũng muốn biết thư viện Zig có thường xuyên có custom build hay không

    • Script build của Zig hoàn toàn là tùy chọn
      Ngay cả khi không có build.zig thì vẫn có thể build/chạy trực tiếp từng file nguồn
      Bạn có thể gắn Zig vào bất kỳ workflow nào dùng GCC hay Clang
      Nhân tiện, Zig cũng hoạt động như một bản thay thế cho C compiler
      Bài viết liên quan

    • Ví dụ tích hợp Bazel với Zig là rules_zig
      Dự án thực tế ZML cũng đang dùng nó
      Dự án ZML

  • Tôi tò mò việc compile và code generation của Zig so với TPDE thế nào
    Nghe nói nó nhanh hơn LLVM -O0 khoảng 10~20 lần, nhưng có vẻ vẫn có giới hạn

  • Tôi cho rằng chiến lược của Zig khá táo bạo
    Nhưng tôi vẫn băn khoăn liệu dùng backend LLVM cho đến bây giờ có còn đúng không
    LLVM có sức cạnh tranh về tốc độ compile và hỗ trợ nền tảng, nhưng về khả năng sinh mã máy tối ưu thì gần như không có đối thủ

    • Chỉ bản build Release mới dùng backend LLVM, còn bản debug thì mặc định dùng cách self-hosted trên những nền tảng được hỗ trợ
      Build debug được lặp lại nhiều lần trong quá trình test thực tế, nên cách này hợp lý hơn

    • Tôi không quá đồng cảm với sự ám ảnh về hiệu năng compiler
      Rốt cuộc đây là bài toán đánh đổi giữa optimization pass (inline, loại bỏ dead code, v.v.) và thời gian compile
      Compiler không tối ưu thì chỉ nhanh lên theo tuyến tính, còn muốn tối ưu sâu hơn thì thời gian tiêu tốn luôn tăng mạnh

    • "Sinh ra assembly xuất sắc" thực ra không phải vấn đề quá quan trọng
      Theo Proebsting's Law, sự tiến bộ của công nghệ compiler chậm hơn rất nhiều so với mức tăng hiệu năng phần cứng
      Kết luận là chỉ cần các tối ưu đơn giản và nhanh cũng đã đủ thực dụng
      LLVM cũng không phải tối ưu tuyệt đối, và khi so với tốc độ compile thì sớm muộn cũng chạm trần

  • Tôi đang làm một thư viện Java bọc thư viện C bằng JNI, nhưng việc build dynamic library cho từng nền tảng quá phiền phức nên đang cân nhắc dùng zig để build đa nền tảng

    • Nếu chỉ là một shim đơn giản, thì trên Java mới dùng Panama và jextract có lẽ sẽ tốt hơn

    • Zig tích hợp sẵn header, mã nguồn libc và cả LLVM riêng, nên cross-compile cực kỳ dễ
      Dễ đến mức gần như không phải lo gì cả

  • Có người thắc mắc vì sao Ghostty hiện vẫn chưa build được bằng backend self-hosted x86_64

    • Compiler Zig bị crash do bug
      Đây vẫn là công nghệ mới nên khá phức tạp, nhưng chắc sớm được xử lý thôi

    • Phần lớn người dùng Ghostty đang ở nền tảng aarch64