New FAMILUG

The PyMiers

Tuesday, 29 November 2022

Rust Cargo release build is not the fastest

By default, cargo build will build a debug binary at ./target/debug/filename, which is helpful for development/debug but without many binary optimizations, thus, runs slow.

When build with cargo build --release, it will build an optimized binary, which is ready for production:

--release                    Build artifacts in release mode, with optimizations

But it still not the fastest it can be.

Cargo profiles

Cargo has 4 builtin profiles: dev, release, test, and bench https://doc.rust-lang.org/cargo/reference/profiles.html which pre-defined build options. User can customize them in Cargo.toml, e.g:

[profile.dev]
opt-level = 1
debug = true

https://doc.rust-lang.org/cargo/reference/profiles.html#lto

Default profile.release sets lto = false.

[profile.release]
opt-level = 3
debug = false
split-debuginfo = '...'  # Platform-specific.
debug-assertions = false
overflow-checks = false
lto = false
panic = 'unwind'
incremental = false
codegen-units = 16
rpath = false

Set lto = true or lto = "fat" will

Performs "fat" LTO which attempts to perform optimizations across all crates within the dependency graph.

which makes build much slower, but the binary often faster 10-20% compare to lto = false. User may try lto = "thin" for faster build but the output still good comparable to lto = "fat"

"thin": Performs "thin" LTO. This is similar to "fat", but takes substantially less time to run while still achieving performance gains similar to "fat".

Reference

Happy building!

Monday, 28 November 2022

Học Rust với gdb

Dùng Rust viết ví dụ để học gdb.

gdb là gì

$ whatis gdb
gdb (1)              - The GNU Debugger

GDB là 1 debugger trên dòng lệnh, mặc dù ít biết tới nhưng nó có cả giao diện TUI - giống như đồ họa trên text. gdb là debugger lừng danh luôn dùng để debug code C. Ngoài C, gdb hỗ trợ nhiều ngôn ngữ bao gồm cả Rust/Go...

What Languages does GDB Support?

GDB supports the following languages (in alphabetical order):

    Ada
    Assembly
    C
    C++
    D
    Fortran
    Go
    Objective-C
    OpenCL
    Modula-2
    Pascal
    Rust

gdb hỗ trợ các ngôn ngữ compile thành binary, còn Python có sẵn pdb cũng tương tự.

Cài gdb trên Ubuntu 20.04

$ sudo apt install -y gdb

Cài Rust trên Ubuntu 20.04

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

theo https://www.rust-lang.org/tools/install

Tạo chương trình Rust đơn giản với stack và heap

Tạo project mới:

$ cargo new gdbplay
     Created binary (application) `gdbplay` package

Sửa nội dung file gdbplay/src/main.rs như sau:

fn main() {
    println!("Hello, world!");
    stack_only(1);
    stack_and_heap(2);
}

fn stack_only(_x: i32) {
    let a = 5;
    println!("{}", a);
}

fn stack_and_heap(_y: i32) {
    let b = 7;
    let p = Box::new(9);
    println!("{} {}", b, p);
}

Debug rust với gdb

Các câu lệnh cơ bản của gdb trong bài:

  • list: in source code ra màn hình
  • b N: đặt breakpoint tại dòng N, debugger sẽ dừng lại khi chạy tới dòng N
  • start: bắt đầu chạy chương trình
  • s: step into - chui vào function
  • c: continue - chạy tới breakpoint tiếp theo.
  • n: next - chạy tới dòng tiếp theo
  • bt: hiển thị backtrace - tất cả các "stackframe"
  • info locals: in ra các biến local
  • info args: in ra các argument của function hiện tại.

help all để xem các câu lệnh khác.

Các câu lệnh gõ vào ở dòng bắt đầu với (gdb)

$ cargo build
   Compiling gdbplay v0.1.0 (/home/hvn/me/familug.github.io/content/gdbplay)
    Finished dev [unoptimized + debuginfo] target(s) in 0.21s
$ gdb target/debug/gdbplay
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
...
Reading symbols from target/debug/gdbplay...
warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts
of file /home/hvn/me/familug.github.io/content/gdbplay/target/debug/gdbplay.
...
(gdb) list
1   fn main() {
2       println!("Hello, world!");
3       stack_only(1);
4       stack_and_heap(2);
5   }
6
7   fn stack_only(_x: i32) {
8       let a = 5;
9       println!("{}", a);
10  }
(gdb) list
11
12  fn stack_and_heap(_y: i32) {
13      let b = 7;
14      let p = Box::new(9);
15      println!("{} {}", b, p);
16
17  }
(gdb) b 7
Breakpoint 1 at 0x9508: file src/main.rs, line 8.
(gdb) b 9
Breakpoint 2 at 0x9510: file src/main.rs, line 9.
(gdb) start
Temporary breakpoint 3 at 0x94a4: file src/main.rs, line 2.
Starting program: /home/hvn/me/familug.github.io/content/gdbplay/target/debug/gdbplay
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Temporary breakpoint 3, gdbplay::main () at src/main.rs:2
2       println!("Hello, world!");
(gdb) n
Hello, world!
3       stack_only(1);
(gdb) s

Breakpoint 1, gdbplay::stack_only (_x=1) at src/main.rs:8
8       let a = 5;
(gdb) n

Breakpoint 2, gdbplay::stack_only (_x=1) at src/main.rs:9
9       println!("{}", a);
(gdb) bt
#0  gdbplay::stack_only (_x=1) at src/main.rs:9
#1  0x000055555555d4e3 in gdbplay::main () at src/main.rs:3
(gdb) info locals
a = 5
(gdb) info args
_x = 1

các biến a hay _x nằm trên stack. Các biến trên stack sẽ tự động được dọn dẹp sau khi hết scope (ở đây là function).

Giờ đổi sang chế độ "TUI", đồ họa trên dòng lệnh, gõ layout next

gdb_tui

p là một "smart pointer" trỏ tới địa chỉ bộ nhớ 0x55555555a3ad0 trên heap. Nếu p là một pointer thông thường như trên C, nó sẽ không tự biến mất khi function kết thúc, và dẫn tới "memleak", lập trình viên phải "free" nó trên code, thì với smart pointer, giá trị 9 mà p trỏ tới sẽ được dọn dẹp khi hết scope (ở đây là function).

x ten_bien để "examine" hay hiển thị giá trị của biến. x /d ten_bien sẽ hiển thị ở dạng số nguyên. Xem thêm tại "help x".

n - next tiếp chạy tới cuối sẽ thấy:

(gdb) n
[Inferior 1 (process 37385) exited normally]
(gdb) n
The program is not being run.

Kết luận

gdb viết tắt các câu lệnh, nhưng khi đã hiểu thì không còn khó. Happy debugging.

Hết.

HVN at http://pymi.vn and https://www.familug.org.

Ủng hộ tác giả 🍺

Monday, 7 November 2022

Cái giá của 2 giờ đầu - hơn 60k

2h

Khi đi làm, giữa muôn vàn công nghệ phức tạp xung quanh, một người làm đủ "cứng" có thể ứng biến dễ dàng:

  • muốn tạo 1 máy ảo và cấu hình mạng dùng terraform? copy file .tf đã tồn tại và sửa một chút cho phù hợp yêu cầu.
  • muốn deploy 1 service với Salt/Ansible? copy các file yaml/role có sẵn rồi sửa một chút cho phù hợp với yêu cầu.
  • muốn deploy 1 service trên Kubernetes? copy file .yaml có sẵn trong "mono repo" của công ty rồi sửa lại chút chút cho phù hợp yêu cầu.
  • muốn thêm 1 endpoint cho website Django/flask? copy function đã có trong cùng file và sửa lại một chút cho hợp với yêu cầu.
  • muốn thêm 1 alert trên Prometheus/Alertmanager? copy vài dòng trong file yaml cấu hình rồi sửa lại một chút cho phù hợp yêu cầu. ...

Mất bao lâu để "làm chủ", "master" các công nghệ bôi đậm nói trên? Không hề ít thời gian và công sức! Vậy làm sao mọi lập trình viên/devops ngày nay đều yêu cầu phải biết cơ bản những thứ này? làm sao họ làm được? đi đường tắt: copy/paste.

Copy/paste trap

Khác với các sinh viên, có cả năm để học 1 môn, hay các "junior" có cả tháng tìm hiểu và "học việc", thì những người làm lâu năm được kỳ vọng nắm được những thứ trên trong vài ngày/tuần, và khi copy/paste + 1 chút search có thể hoàn thành công việc rồi lại chuyển qua thứ khác, khiến họ dễ mắc phải bẫy "YAML/TF engineer" - hiểu nôm na và biết copy/paste.

Local knowledge

Nếu làm công ty nhỏ, 1 người có thời gian xây dựng cả hệ thống từ đầu, làm những công việc như:

  • tạo 1 project từ đầu "manage.py startproject"
  • setup CI/CD, config GitLab/Jenkins, etc...
  • cài đặt terraform + terraform enterprise/S3 state management
  • tạo cloud Virtual Network/VPC, chia subnet, config route...
  • setup Kubernetes cluster, config ServiceAccount/Role, ...
  • ...

Thì ở các công ty lớn, mỗi người chỉ nắm 1 phần nhỏ, với các hệ thống đã dựng sẵn, và nếu không có kinh nghiệm từ trước, thì họ chỉ có kinh nghiệm "từ ấy".

Rocket 2 giờ

Giải pháp để tránh bẫy hiểu biết cục bộ hay "get shit done" này là dành 2 giờ đầu (hay 4, hay nhiều hơn, trong phạm vi có thể) để hiểu từng công nghệ, tự setup theo tutorial của công nghệ ấy. Việc đầu tư chút thời gian này sẽ có giá trị rất cao về sau... đặc biệt là trong các cuộc phỏng vấn.

Chuyện này chẳng có gì mới, bài học kinh điển của những người "tiết kiệm thời gian", không đọc kỹ document, để rồi mất hàng tháng/tuần/ngày để debug về sau.

Kết luận

Giành vài giờ tự setup từ đầu theo tutorial trước khi dùng 1 công nghệ sẽ mang lại lợi ích lớn về sau.

Hết.

HVN at http://pymi.vn and https://www.familug.org.

Ủng hộ tác giả 🍺