Rust
Öbek ayırıcı
Kendi bellek ayırıcını unsafe ile yazarsın.
Bitirme görevi: öbek ayırıcı
Uzman seviyenin ilk bitirme görevi: programın tüm heap ayırmalarını sayan bir küresel ayırıcı. GlobalAlloc trait'i iki zorunlu metot ister: alloc ve dealloc. Sistem ayırıcısını sarıp her çağrıda atomik sayaçları güncelleyeceğiz:
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
struct Sayan;
static ADET: AtomicUsize = AtomicUsize::new(0);
static BAYT: AtomicUsize = AtomicUsize::new(0);
unsafe impl GlobalAlloc for Sayan {
unsafe fn alloc(&self, l: Layout) -> *mut u8 {
ADET.fetch_add(1, Ordering::Relaxed);
BAYT.fetch_add(l.size(), Ordering::Relaxed);
unsafe { System.alloc(l) }
}
unsafe fn dealloc(&self, p: *mut u8, l: Layout) {
unsafe { System.dealloc(p, l) }
}
}
#[global_allocator]
static AYIRICI: Sayan = Sayan;
Bir bloğu ölçmek
Sayaçların bloktan önceki ve sonraki farkı, o bloğun ayırmalarını verir. Ölçüm sırasında yazdırma yapmamak önemlidir, çünkü println! de ayırma yapabilir:
let (a0, b0) = (ADET.load(Ordering::Relaxed), BAYT.load(Ordering::Relaxed));
{
let v: Vec<u8> = Vec::with_capacity(100);
std::hint::black_box(&v);
}
let (a1, b1) = (ADET.load(Ordering::Relaxed), BAYT.load(Ordering::Relaxed));
println!("{} {}", a1 - a0, b1 - b0); // 1 100
Bu teknik, sıcak döngülerdeki gereksiz ayırmaları bulmak için kullanılır; dhat crate'i aynı fikrin ayrıntılı bir sürümüdür.
Uygulama Sayan ayırıcı
Yukarıdaki Sayan ayırıcısını yaz ve kaydet. Vec::<u8>::with_capacity(100) oluşturan bir bloğun ayırma sayısını ve bayt miktarını, ölçüm sırasında yazdırma yapmadan hesapla ve boşlukla yazdır.
Örnek çözümü göster
use std::alloc::{GlobalAlloc, Layout, System};
use std::sync::atomic::{AtomicUsize, Ordering};
struct Sayan;
static ADET: AtomicUsize = AtomicUsize::new(0);
static BAYT: AtomicUsize = AtomicUsize::new(0);
unsafe impl GlobalAlloc for Sayan {
unsafe fn alloc(&self, l: Layout) -> *mut u8 {
ADET.fetch_add(1, Ordering::Relaxed);
BAYT.fetch_add(l.size(), Ordering::Relaxed);
// SAFETY: sözleşme çağırandan System'e aynen aktarılır.
unsafe { System.alloc(l) }
}
unsafe fn dealloc(&self, p: *mut u8, l: Layout) {
// SAFETY: p, aynı layout ile System'den alınmıştı.
unsafe { System.dealloc(p, l) }
}
}
#[global_allocator]
static AYIRICI: Sayan = Sayan;
fn main() {
let (a0, b0) = (ADET.load(Ordering::Relaxed), BAYT.load(Ordering::Relaxed));
{
let v: Vec<u8> = Vec::with_capacity(100);
std::hint::black_box(&v);
}
let (a1, b1) = (ADET.load(Ordering::Relaxed), BAYT.load(Ordering::Relaxed));
println!("{} {}", a1 - a0, b1 - b0);
}
Kendini test et
-
Ayırıcının içinde <code>println!</code> ya da <code>Vec</code> kullanmak neden tehlikelidir?
- Onlar da ayırma yapabilir; ayırıcı kendini özyinelemeli çağırıp kilitlenir ya da taşar
- Yavaştır
- Derlenmez
- Tehlikeli değildir
Cevabı göster
Onlar da ayırma yapabilir; ayırıcı kendini özyinelemeli çağırıp kilitlenir ya da taşar — Ayırıcı yalnızca ayırma gerektirmeyen işlemler yapmalı: atomik sayaçlar ideal.
-
Küresel ayırıcıyı kaydet
#[____]
static AYIRICI: Sayan = Sayan;
Cevabı göster
#[global_allocator]
static AYIRICI: Sayan = Sayan;
-
Öğe ve görevi
- GlobalAlloc
- Ayırıcı trait'i
- Layout
- Boyut ve hizalama
- System
- İşletim sistemi ayırıcısı
- #[global_allocator]
- Kayıt
Sıradaki ders: SIMD matris