6.2 KiB
6.2 KiB
Phase 11.5b: Atomic操作最適化によるsync処理高速化
🎯 目標
Arcの重いロック操作を、可能な限り軽量なatomic操作に置き換えて性能を向上させる。
📊 現状の問題
現在の実装
// すべてのBox操作でMutexロック
pub fn get_field(&self, name: &str) -> Option<Box<dyn NyashBox>> {
let fields = self.fields.lock().unwrap(); // 重い!
fields.get(name).cloned()
}
// Read-onlyでも同じコスト
pub fn to_string(&self) -> String {
let value = self.value.lock().unwrap(); // 不要なロック!
value.clone()
}
パフォーマンス問題
- Read操作でも排他ロックのオーバーヘッド
- 複数スレッドでのcontention
- Cache line bouncing
🚀 実装計画
Step 1: Read-only path分析
// mir/readonly_analysis.rs
pub struct ReadOnlyAnalysis {
// メソッドのread-only性
readonly_methods: HashMap<(TypeId, String), bool>,
// フィールドのimmutability
immutable_fields: HashMap<(TypeId, String), bool>,
}
impl ReadOnlyAnalysis {
pub fn analyze_box_types(&mut self, registry: &BoxRegistry) {
// StringBox.length() -> read-only
self.mark_readonly("StringBox", "length");
self.mark_readonly("StringBox", "isEmpty");
// IntegerBox.value() -> read-only
self.mark_readonly("IntegerBox", "value");
// プラグインメソッドも解析
self.analyze_plugin_methods();
}
}
Step 2: Atomic wrapper実装
// runtime/atomic_box.rs
pub struct AtomicBox<T: NyashBox> {
// Read-optimized RwLock
inner: Arc<RwLock<T>>,
// Atomic cache for immutable data
cached_string: AtomicPtr<String>,
cached_int: AtomicI64,
}
impl<T: NyashBox> AtomicBox<T> {
/// Lock-free read for cached values
pub fn read_cached(&self) -> Option<Box<dyn NyashBox>> {
// Atomic loadでキャッシュチェック
let ptr = self.cached_string.load(Ordering::Acquire);
if !ptr.is_null() {
unsafe {
let s = &*ptr;
return Some(Box::new(StringBox::new(s.clone())));
}
}
None
}
/// Optimized read path
pub fn read_optimized<F, R>(&self, f: F) -> R
where
F: FnOnce(&T) -> R
{
// Try read lock first (non-blocking)
if let Ok(guard) = self.inner.try_read() {
return f(&*guard);
}
// Fallback to regular read
let guard = self.inner.read().unwrap();
f(&*guard)
}
}
Step 3: JIT最適化
// jit/lower/atomic_opt.rs
impl<'a> LoweringBuilder<'a> {
fn emit_box_method_call(&mut self,
box_val: Value,
method: &str,
args: &[Value]
) -> Value {
// Read-only解析結果確認
if self.readonly_info.is_readonly_method(box_val, method) {
// Atomic fast path
self.emit_atomic_read_path(box_val, method, args)
} else {
// 通常のMutexパス
self.emit_mutex_path(box_val, method, args)
}
}
fn emit_atomic_read_path(&mut self,
box_val: Value,
method: &str,
args: &[Value]
) -> Value {
// 1. Atomic loadでcacheチェック
let cache_ptr = self.emit_atomic_load(box_val, "cache");
// 2. Cache hit判定
let is_valid = self.emit_null_check(cache_ptr);
// 3. 条件分岐
let then_block = self.create_block();
let else_block = self.create_block();
self.emit_branch(is_valid, then_block, else_block);
// Cache hit: lock-free return
self.switch_to_block(then_block);
let cached = self.emit_load(cache_ptr);
self.emit_jump(merge_block);
// Cache miss: RwLock読み取り
self.switch_to_block(else_block);
let value = self.emit_rwlock_read(box_val, method);
self.emit_jump(merge_block);
// Merge
self.switch_to_block(merge_block);
self.emit_phi(vec![(cached, then_block), (value, else_block)])
}
}
Step 4: Memory ordering最適化
// プラットフォーム別最適化
#[cfg(target_arch = "x86_64")]
fn emit_memory_fence(&mut self, ordering: Ordering) {
match ordering {
Ordering::Relaxed => {}, // x86は強いメモリモデル
Ordering::Acquire => self.emit_lfence(),
Ordering::Release => self.emit_sfence(),
Ordering::SeqCst => self.emit_mfence(),
}
}
#[cfg(target_arch = "aarch64")]
fn emit_memory_fence(&mut self, ordering: Ordering) {
// ARMは弱いメモリモデル
match ordering {
Ordering::Relaxed => {},
Ordering::Acquire => self.emit_dmb_ld(),
Ordering::Release => self.emit_dmb_st(),
Ordering::SeqCst => self.emit_dmb(),
}
}
📈 期待される効果
ベンチマーク
// Read-heavy workload
function sumStringLengths(strings) {
local total = 0
loop(s in strings) {
total = total + s.length() // Atomic最適化
}
return total
}
// 性能改善
// Before: 1000ms (Mutex contention)
// After: 100ms (Lock-free reads)
改善予測
- Read操作: 90%高速化
- Read/Write混在: 50%高速化
- マルチスレッド: スケーラビリティ大幅向上
🔍 検証方法
1. Lock統計
{
"total_operations": 100000,
"mutex_locks": 10000,
"atomic_reads": 90000,
"lock_reduction": 0.9,
"contention_events": 50
}
2. プロファイリング
# Mutexプロファイル
NYASH_PROFILE_LOCKS=1 ./target/release/nyash bench.nyash
# Atomic最適化後
NYASH_ATOMIC_OPT=1 ./target/release/nyash bench.nyash
🚧 実装上の注意点
-
正確性
- Memory orderingの正しさ
- ABA問題の回避
- Weak pointer対応
-
互換性
- 既存APIの維持
- プラグインとの相互運用
-
デバッグ性
- Race condition検出
- Lock順序の追跡
🎉 完了基準
- Read-only分析実装
- AtomicBox wrapper実装
- JIT統合
- マルチスレッドベンチマーク
- プラットフォーム別最適化