mcpField
M
matlab-optimize-performance

matlab-optimize-performance

github.com/matlab開発1.2k90 回インストール1 日前に更新
リポジトリ

matlab-optimize-performance について

MATLAB の性能を改善するための体系的なスキルです。プロファイリングによるボトルネックの特定、改善策の選択、再計測、正しさの確認を関数・スクリプト・GPUコードで行います。

主な機能

  1. 01実行時間の基準値を測定
  2. 02プロファイラーでボトルネックを特定
  3. 03分析結果に基づく最適化策の選択
  4. 04再計測と性能変化の算出
  5. 05出力の同等性を検証
  6. 06最適化結果の報告

活用シーン

  1. 01MATLAB関数やスクリプトの遅い箇所の特定
  2. 02コード変更前後の実行時間比較
  3. 03GPUコードの実行性能測定
  4. 04ループ内の配列拡張や重複処理の最適化

インストール

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

$npx skills add https://github.com/matlab/matlab-agentic-toolkit --skill matlab-optimize-performance

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

同梱ファイル

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

manifest.yaml
references/
measurement-templates.md
optimization-patterns.md

詳細

MATLAB パフォーマンス最適化ワークフロー

MATLAB コードのパフォーマンスボトルネックを特定して解消するための、体系的な7ステップのワークフローです。

使用する場面

  • MATLAB コードの高速化や最適化を求められた場合
  • MATLAB コードが遅い原因を調べたい場合
  • 実行に時間がかかりすぎる関数やスクリプトがある場合
  • MATLAB コードのベンチマークや実行時間の計測を求められた場合
  • 変更の前後でパフォーマンスを比較したい場合
  • MATLAB のパフォーマンスに関するベストプラクティスを尋ねられた場合

使用しない場面

  • Simulink モデルのシミュレーション速度を最適化する場合(Simulink Profiler を使用してください)
  • ボトルネックが、M コードレベルでは変更できないコンパイル済みの C/MEX コードにある場合
  • パフォーマンスの問題が純粋に I/O に起因する場合(ファイル読み込み、ネットワーク、データベース)
  • パフォーマンスのテストを作成したい場合(writing-matlab-perf-tests スキルを使用してください)

7ステップのワークフロー

ステップ1:ベースラインを確立する

改善の基準となる数値を得るために、現在のパフォーマンスを測定します。

単一の関数の場合:

f = @() targetFunction(input1, input2);
baseline = timeit(f);
fprintf('Baseline: %.4f s\n', baseline);

GPU コードの場合:

f = @() gpuFunction(gpuInput);
baseline = gputimeit(f);

スクリプトまたは複数ステップのワークフローの場合:

% Warmup run (first call includes JIT compilation)
myWorkflow(inputs);

% Timed run
tic;
myWorkflow(inputs);
baseline = toc;
fprintf('Baseline: %.4f s\n', baseline);

timeit はウォームアップを処理し、複数のサンプルを自動的に実行するため、推奨されます。

ステップ2:プロファイルして分析する

実際にどこで時間が使われているかを特定します。推測してはいけません。必ずプロファイルしてください。

profile on;
targetFunction(input1, input2);
profile off;
profile viewer;

プロファイラーの結果の読み方:

  1. 関数の概要 — 関数ごとの合計時間と自己時間が表示されます。自己時間とは、その関数内で費やされた時間であり、呼び出し先の関数に費やされた時間は含みません。まず、自己時間が最も長い関数を確認します。
  2. 行ごとの詳細 — 関数名をクリックすると、各行で費やされた時間を確認できます。これにより、ボトルネックとなっている具体的な行がわかります。
  3. 呼び出し回数 — 数千回、数百万回と呼び出される関数は、最適化の有力な候補です。

ヒント:

  • コードの実行が非常に速い場合は、プロファイラーが十分なサンプルを収集できるよう、ループ内で複数回実行します。
  • 真のボトルネックを見つけるには、合計時間ではなく自己時間を確認します。
  • 関数を詳しく調べます。概要ページだけでは全体像の一部しかわかりません。
ステップ3:最適化の機会を特定する

プロファイリング結果をもとに、該当するパターンを特定します。パターンの全一覧については、references/optimization-patterns.md を参照してください。

効果の大きいパターン:

パターン典型的な高速化確認する項目
ベクトル化2–200x配列に対して要素ごとの計算を行うループ
事前割り当て2–100xループ内で配列を拡張している(x = [x; newRow])
不要な再計算2–50x同じコストの高い式を複数回計算している
discretize/histcounts2–50xデータのビニングや分類を行うループ
永続キャッシュ1.5–95xload() の繰り返しやコストの高いオブジェクト生成
論理インデックス1.2–5x配列のインデックス指定だけを目的に find() を使用している
arguments ブロック1.1–1.8xinputParser を使用している関数
代数的簡略化1.5–3x冗長な sqrt、abs、または行列演算

最適化の前に、対象が改善に値するか確認します。

  • 自己時間は合計時間の10%を超えていますか? そうでなければ、最適化しても効果はあまりありません。
  • 頻繁に繰り返すループ内で呼び出されていますか? 呼び出し回数が多く、1回あたりの時間が短くても、合計時間は大きくなります。
  • M コードですか、それとも組み込み関数ですか? 組み込み関数自体を高速化することはできませんが、呼び出し回数を減らせる場合があります(例:列ごとにループする代わりに、行列を filtfilt/filter に渡す)。
ステップ4:最適化を実装する

ステップ3で特定したパターンを適用します。前後のコード例を含む全一覧については、references/optimization-patterns.md を参照してください。

一般原則:

  • プロファイリングで特定した、最も効果の大きいパターンから着手します。
  • ループ内の不変な処理をループの外に移動します(オブジェクト生成、オプションの解析、定数式など)。
  • 可能な場合は、要素ごとのループを配列演算に置き換えます。
  • 手書きの同等処理ではなく、目的に特化した関数(discretize、cumsum、hypot)を使用します。
  • 大規模なデータでは、メモリ使用量を抑えるためにベクトル化をバッチ処理します(一覧のパターン9を参照)。

例 — 不変な処理をループの外に移動する:

% Before: repeated expensive setup
for i = 1:n
    opts = optimoptions('fminunc', 'Display', 'off');
    result(i) = fminunc(@(x) cost(x, data(i)), x0, opts);
end

% After: setup once
opts = optimoptions('fminunc', 'Display', 'off');
for i = 1:n
    result(i) = fminunc(@(x) cost(x, data(i)), x0, opts);
end
ステップ 5:最適化後のパフォーマンスを測定する

ステップ 1 と同じ方法で再測定します。

f = @() optimizedFunction(input1, input2);
optimized = timeit(f);
speedup = baseline / optimized;
fprintf('Optimized: %.4f s (%.2fx speedup)\n', optimized, speedup);

1.2 倍以上の高速化は有意と見なされます。それ未満の場合、測定ノイズにより、変更の効果を確信するのが難しくなります。

ステップ 6:正しさを検証する

すべての最適化で、元のコードと同じ結果が得られる必要があります。

original = originalFunction(input1, input2);
fast = optimizedFunction(input1, input2);

% Numeric comparison (allows floating-point tolerance)
maxErr = max(abs(original(:) - fast(:)));
fprintf('Max error: %.2e\n', maxErr);
assert(maxErr < 1e-10, 'Results differ beyond tolerance!');

数値以外の出力の場合:

assert(isequal(original, fast), 'Results differ!');

浮動小数点演算の順序変更(例:合計する順序の変更)が原因で結果にわずかな差が生じる場合、通常は許容できます。許容誤差を明記してください。

ステップ 7:結果を報告する

実施した内容と達成した改善をまとめます。

fprintf('\n=== Performance Optimization Report ===\n');
fprintf('Target: %s\n', funcName);
fprintf('Baseline: %.4f s\n', baseline);
fprintf('Optimized: %.4f s\n', optimized);
fprintf('Speedup: %.2fx\n', speedup);
fprintf('Correctness: max error = %.2e\n', maxErr);
fprintf('Pattern applied: %s\n', patternName);

複数の最適化を行った場合は、それぞれの高速化と、エンドツーエンドでの全体的な改善を個別に報告してください。

重要なルール

  1. 最適化の前に必ずプロファイリングする — ボトルネックの場所を推測しないでください
  2. 一度に変更するのは 1 つだけ — 各最適化の後に測定し、効果があった変更を把握してください
  3. 正しさを検証する — すべての最適化で同等の出力が得られる必要があります
  4. 1.2 倍のしきい値 — 1.2 倍未満の高速化は、ノイズと確実に区別できません
  5. GPU の計測 — GPU コードの計測前後には必ず wait(gpuDevice) を実行してください
  6. timeit を使用する — ウォームアップと平均化を処理します。ベンチマークには生の tic/toc を使わないでください

よくある間違い

間違い問題点代わりに行うこと
プロファイリングせずに最適化する間違った箇所を修正することになりますまずプロファイリングします(ステップ 2)
ウォームアップせずに 1 回だけ tic/toc を実行するJIT コンパイル時間が含まれますtimeit を使うか、ウォームアップ用の呼び出しを追加します
同期せずに GPU コードを計測するGPU 演算は非同期なので、toc が早く実行されます実行前後に wait(gpuDevice) を実行します
ループ内で配列を拡張する追加のたびに配列全体がコピーされますループの前に事前割り当てします
大きな配列をむやみにベクトル化するメモリを超過する可能性があります大きなデータにはチャンク処理を使います
サブ関数の高速化だけを報告するサブ関数が全体の 5%を占める場合、誤解を招きますエンドツーエンドの計測時間を必ず報告します
高速化すれば正しいと思い込む処理を省略するなどのバグで、コードが高速になることがあります結果が一致することを必ず検証します(ステップ 6)

参考ファイル

  • references/optimization-patterns.md — コード例と測定済みの高速化を含む、最適化パターンの全カタログ
  • references/measurement-templates.md — ワークフローの各ステップでそのまま使える MATLAB スクリプトのテンプレート

著作権 2026 The MathWorks, Inc.

コメント