.NET9 Pre7 DATAS+Rustc Compile线程续

文摘   2024-08-25 12:37   湖北  

点击上方蓝字 江湖评谈设为关注/星标





.NET9 PreView7 DATAS

.NET 9中引入的动态适应应用程序大小(DATAS)功能。DATAS旨在根据应用程序的内存需求自动调整堆大小,使其与长期存活数据的大小大致成正比。这与现有的服务器垃圾回收(Server GC)模式有所不同,后者关注的是提高吞吐量,而不是根据应用程序的大小来调整堆。

DATAS的优势在于:适应不同硬件配置下的应用程序堆大小,使堆大小在不同规格的机器上保持一致或相似。根据工作负载的变化自动调整堆大小,特别是在内存受限的环境中,这有助于在某些进程的工作负载减轻时容纳更多进程。有助于容量规划。

DATAS功能的实现方法包括:

根据长期存活数据的大小设置触发下一次垃圾回收前的最大分配量,以限制堆大小。根据吞吐量设置实际允许的分配量。根据需要调整堆的数量,实现工作站垃圾回收(最少一个堆)和服务器垃圾回收(与机器核心数匹配)之间的混合模式。在需要时执行完全压缩垃圾回收,以防止碎片过多,同时也有助于限制堆大小。

基准测试结果显示,在48核Linux机器上运行基准测试时,工作集显著减少,最大吞吐量(以rps计)降低了约2-3%,但工作集改善了80%以上。启用DATAS后,Gen0和Gen1垃圾回收次数显著增加。


Rust Compile线程详细

继续Rustc的Compile线程,由于llvm或者rustc底板编译器生成的汇编格式在优化之后,一时还不太习惯。一般都类似于这种:

mov rax [rip+0x100]call rax

而传递的参数,往往是不是rdi,rsi这种,它直接用rip+偏移取代了。这种情况在rustc里面到处都是。

创建一个线程,这里的新线程入口是thread_start,参数是p。

///rust/library/std/src/sys/pal/unix/thread.rs:84let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);

下面的main参数应是上面的p参

//library/std/src/sys/pal/unix/thread.rsextern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {    unsafe {                let _handler = stack_overflow::Handler::new();                Box::from_raw(main as *mut Box<dyn FnOnce()>)();            }            ptr::null_mut()}

as *mut Box<dyn FnOnce()> 将 main 函数的地址转换为一个指向 Box<dyn FnOnce()> 类型的可变指针。Box::from_raw 是 Rust 标准库中的一个函数,用于从原始指针创建一个 Box<T>。这里它用于从 main 函数的地址创建一个指向 Box<dyn FnOnce()> 的 Box。

FnOnce如下:

// library/core/src/ops/function.rs#[lang = "fn_once"]#[stable(feature = "rust1", since = "1.0.0")]#[rustc_paren_sugar]#[rustc_on_unimplemented(    on(        Args = "()",        note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"    ),    on(        _Self = "unsafe fn",        note = "unsafe function cannot be called generically without an unsafe block",        // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string        label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"    ),    message = "expected a `{Trait}` closure, found `{Self}`",    label = "expected an `{Trait}` closure, found `{Self}`")]#[fundamental] // so that regex can rely that `&str: !FnMut`#[must_use = "closures are lazy and do nothing unless called"]// FIXME(effects) #[const_trait]pub trait FnOnce<Args: Tuple> {    /// The returned type after the call operator is used.    #[lang = "fn_once_output"]    #[stable(feature = "fn_once_output", since = "1.12.0")]    type Output;
/// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] extern "rust-call" fn call_once(self, args: Args) -> Self::Output;}

其call_once调用如下:

//library/std/src/sys/backtrace.rs:154#[inline(never)]pub fn __rust_begin_short_backtrace<F, T>(f: F) -> Twhere    F: FnOnce() -> T,{    let result = f();    std::hint::black_box(());    result}

这里就体现了上面说的ASM格式,比如f():

 0x7ffff0b86530 <+0>:  push   rax->  0x7ffff0b86531 <+1>:  call   qword ptr [rip + 0x700a7e9]    0x7ffff0b86537 <+7>:  and    al, 0x1    0x7ffff0b86539 <+9>:  pop    rcx    0x7ffff0b8653a <+10>: ret

通过传递的参数调取相应的处理,比如IR变异,机器码生成等等。有的rust函数调用了glibc,比如f(),如果感到疑惑,可以di命令查看其所有汇编代码分析。

往期精彩回顾

Rustc Compile过程+线程

Rust编译器研究+.NET9 PreView7

江湖评谈
记录,分享,自由。
 最新文章