mcpField
R
rust-performance

rust-performance

github.com/huiali開発4739 回インストール37 週間前に更新
リポジトリ

rust-performance について

rust-performance は、Rust プログラムを最適化する開発者向けのスキルです。プロファイリングを起点とする手順に加え、アルゴリズム、データ構造、割り当て、キャッシュ、並行処理、NUMA の調整方法を扱います。

主な機能

  1. 01プロファイリングとベンチマークの手順
  2. 02アルゴリズムとデータ構造の選定
  3. 03メモリ割り当てとクローンの削減
  4. 04並列処理とキャッシュの調整
  5. 05競合と NUMA の影響の診断

活用シーン

  1. 01CPU やメモリのホットスポット特定
  2. 02Rust コードの割り当てコスト削減
  3. 03並行プログラムのロック競合の調査
  4. 04ベンチマークによる性能変更の評価

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/huiali/rust-skills --skill rust-performance

インストール後、Claude Code で/rust-performanceを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

SKILL_EN.md
SKILL_ZH.md
agents/
openai.yaml

詳細

最適化の優先順位

1. Algorithm choice      (10x - 1000x)   ← Biggest impact
2. Data structure        (2x - 10x)
3. Reduce allocations    (2x - 5x)
4. Cache optimization    (1.5x - 3x)
5. SIMD/parallelism      (2x - 8x)

警告:早すぎる最適化は諸悪の根源です。まず動作する状態にしてから、ホットパスを最適化してください。

解決パターン

パターン 1:事前割り当て
// ❌ Bad: grows dynamically
let mut vec = Vec::new();
for i in 0..1000 {
    vec.push(i);
}

// ✅ Good: pre-allocate known size
let mut vec = Vec::with_capacity(1000);
for i in 0..1000 {
    vec.push(i);
}
パターン 2:不要なクローンを避ける
// ❌ Bad: unnecessary clone
fn process(item: &Item) {
    let data = item.data.clone();
    // use data...
}

// ✅ Good: use reference
fn process(item: &Item) {
    let data = &item.data;
    // use data...
}
パターン 3:バッチ処理
// ❌ Bad: multiple database calls
for user_id in user_ids {
    db.update(user_id, status)?;
}

// ✅ Good: batch update
db.update_all(user_ids, status)?;
パターン 4:小さなオブジェクトの最適化
use smallvec::SmallVec;

// ✅ No heap allocation for ≤16 items
let mut vec: SmallVec<[u8; 16]> = SmallVec::new();
パターン 5:並列処理
use rayon::prelude::*;

let sum: i32 = data
    .par_iter()
    .map(|x| expensive_computation(x))
    .sum();

プロファイリングツール

ツール目的
cargo benchCriterion ベンチマーク
perf / flamegraphCPU フレームグラフ
heaptrackメモリ割り当ての追跡
valgrind --tool=cachegrindキャッシュ分析
dhatヒープ割り当てのプロファイリング

一般的な最適化

修正すべきアンチパターン
アンチパターン問題点適切な方法
ライフタイムを避けるためにクローンするパフォーマンスコスト適切な所有権設計
すべてを Box に入れる間接参照のオーバーヘッドスタック割り当てを優先
小さなデータに HashMap を使うハッシュのオーバーヘッドが大きすぎるVec + 線形検索
ループ内で文字列を連結するO(n²)with_capacity または format!
LinkedListキャッシュ効率が悪いVec または VecDeque

応用:偽共有

症状
// ❌ Problem: multiple AtomicU64 in one struct
struct ShardCounters {
    inflight: AtomicU64,
    completed: AtomicU64,
}
  • 1 つの CPU コアが 90% 以上
  • perf で LLC ミス率が高い
  • アトミックな RMW 操作が多い
  • スレッドを追加すると遅くなる
診断
# Perf analysis
perf stat -d your_program
# Look for LLC-load-misses and locked-instrs

# Flamegraph
cargo flamegraph
# Find atomic fetch_add hotspots
解決策:キャッシュラインのパディング
// ✅ Each field in separate cache line
#[repr(align(64))]
struct PaddedAtomicU64(AtomicU64);

struct ShardCounters {
    inflight: PaddedAtomicU64,
    completed: PaddedAtomicU64,
}

ロック競合の最適化

症状
// ❌ All threads compete for single lock
let shared: Arc<Mutex<HashMap<String, usize>>> =
    Arc::new(Mutex::new(HashMap::new()));
  • 時間の大半が mutex のロック/アンロックに費やされる
  • スレッド数を増やすとパフォーマンスが低下する
  • システム時間の割合が高い
解決策:スレッドローカルシャーディング
// ✅ Each thread has local HashMap, merge at end
pub fn parallel_count(data: &[String], num_threads: usize)
    -> HashMap<String, usize>
{
    let mut handles = Vec::new();

    for chunk in data.chunks(data.len() / num_threads) {
        handles.push(thread::spawn(move || {
            let mut local = HashMap::new();
            for key in chunk {
                *local.entry(key.clone()).or_insert(0) += 1;
            }
            local  // Return local counts
        }));
    }

    // Merge all local results
    let mut result = HashMap::new();
    for handle in handles {
        for (k, v) in handle.join().unwrap() {
            *result.entry(k).or_insert(0) += v;
        }
    }
    result
}

NUMA 対応

問題
// Multi-socket server, memory allocated on remote NUMA node
let pool = ArenaPool::new(num_threads);
// Rayon work-stealing causes tasks to run on any thread
// Cross-NUMA access causes severe memory migration latency
解決策
// 1. NUMA node binding
let numa_node = detect_numa_node();
let pool = NumaAwarePool::new(numa_node);

// 2. Use unified allocator (jemalloc)
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

// 3. Avoid cross-NUMA object clones
// Borrow directly, don't copy data
ツール
# Check NUMA topology
numactl --hardware

# Bind to NUMA node
numactl --cpunodebind=0 --membind=0 ./my_program

データ構造の選択

シナリオ選択肢理由
高並行性の書き込みDashMap またはシャーディングロック競合を減らす
読み取りが多く、書き込みが少ないRwLock読み取りロックは処理をブロックしない
小規模なデータセットVec + 線形検索HashMap のオーバーヘッドのほうが大きい
キーが固定Enum + arrayハッシュのオーバーヘッドがゼロ
読み取り中心の例
// ✅ Many reads, few updates
struct Config {
    map: RwLock<HashMap<String, ConfigValue>>,
}

impl Config {
    pub fn get(&self, key: &str) -> Option<ConfigValue> {
        self.map.read().unwrap().get(key).cloned()
    }

    pub fn update(&self, key: String, value: ConfigValue) {
        self.map.write().unwrap().insert(key, value);
    }
}

よくあるパフォーマンス上の落とし穴

落とし穴症状解決策
隣接するアトミック変数偽共有#[repr(align(64))]
グローバル Mutexロック競合スレッドローカル + マージ
NUMA ノードをまたぐ割り当てメモリ移行NUMA 対応の割り当て
小さな割り当ての頻発アロケーターへの負荷オブジェクトプーリング
動的な文字列キー余分な割り当て整数 ID を使用

レビューチェックリスト

パフォーマンスを最適化する場合:

  • プロファイリングを実施してボトルネックを特定した
  • 測定によってボトルネックを確認した
  • アルゴリズムがユースケースに対して最適である
  • データ構造が適切である
  • 不要な割り当てを削除した
  • 効果がある箇所で並列性を活用した
  • キャッシュ効率のよいデータ配置にした
  • ロック競合を最小限に抑えた
  • ベンチマークで改善を確認した
  • コードの読みやすさと保守性を維持した

検証コマンド

# Benchmark
cargo bench

# Profile with perf
perf stat -d ./target/release/your_program

# Generate flamegraph
cargo flamegraph --release

# Heap profiling
valgrind --tool=dhat ./target/release/your_program

# Cache analysis
valgrind --tool=cachegrind ./target/release/your_program

# NUMA topology
numactl --hardware

よくある落とし穴

1. 早すぎる最適化

症状:プロファイリングの前に最適化する

対処法:まずプロファイリングを行い、ホットパスだけを最適化する

2. 実行頻度の低いパスのマイクロ最適化

症状:めったに実行されないコードに時間をかける

対処法:ホットループに注力する(コードの 10% が実行時間の 90% を占める)

3. わずかな改善のために可読性を犠牲にする

症状:5% 未満の改善のためにコードが複雑になる

対処法:改善幅が大きい場合(20% 超)にのみ最適化する

パフォーマンス診断ワークフロー

1. Identify symptom (slow, high CPU, high memory)
   ↓
2. Profile with appropriate tool
   - CPU → perf/flamegraph
   - Memory → heaptrack/dhat
   - Cache → cachegrind
   ↓
3. Find hotspot (function/line)
   ↓
4. Understand why it's slow
   - Algorithm? Data structure? Allocation?
   ↓
5. Apply targeted optimization
   ↓
6. Benchmark to confirm improvement
   ↓
7. Repeat if not fast enough

関連スキル

  • rust-concurrency - 並列処理パターン
  • rust-async - 非同期パフォーマンスの最適化
  • rust-unsafe - unsafe によるゼロコスト抽象化
  • rust-coding - 高パフォーマンスなイディオムに沿ったコードの記述
  • rust-anti-pattern - 避けるべきパフォーマンスのアンチパターン

ローカライズ版リファレンス

  • 中国語版:SKILL_ZH.md - すべての内容を含む完全版

コメント