matlab-optimize-performance について
MATLAB の性能を改善するための体系的なスキルです。プロファイリングによるボトルネックの特定、改善策の選択、再計測、正しさの確認を関数・スクリプト・GPUコードで行います。
主な機能
- 01実行時間の基準値を測定
- 02プロファイラーでボトルネックを特定
- 03分析結果に基づく最適化策の選択
- 04再計測と性能変化の算出
- 05出力の同等性を検証
- 06最適化結果の報告
活用シーン
- 01MATLAB関数やスクリプトの遅い箇所の特定
- 02コード変更前後の実行時間比較
- 03GPUコードの実行性能測定
- 04ループ内の配列拡張や重複処理の最適化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ matlab/ matlab-agentic-toolkit --skill matlab-optimize-performanceインストール後、Claude Code で/matlab-optimize-performanceを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
manifest.yamlreferences/measurement-templates.mdoptimization-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;
プロファイラーの結果の読み方:
- 関数の概要 — 関数ごとの合計時間と自己時間が表示されます。自己時間とは、その関数内で費やされた時間であり、呼び出し先の関数に費やされた時間は含みません。まず、自己時間が最も長い関数を確認します。
- 行ごとの詳細 — 関数名をクリックすると、各行で費やされた時間を確認できます。これにより、ボトルネックとなっている具体的な行がわかります。
- 呼び出し回数 — 数千回、数百万回と呼び出される関数は、最適化の有力な候補です。
ヒント:
- コードの実行が非常に速い場合は、プロファイラーが十分なサンプルを収集できるよう、ループ内で複数回実行します。
- 真のボトルネックを見つけるには、合計時間ではなく自己時間を確認します。
- 関数を詳しく調べます。概要ページだけでは全体像の一部しかわかりません。
ステップ3:最適化の機会を特定する
プロファイリング結果をもとに、該当するパターンを特定します。パターンの全一覧については、references/optimization-patterns.md を参照してください。
効果の大きいパターン:
| パターン | 典型的な高速化 | 確認する項目 |
|---|---|---|
| ベクトル化 | 2–200x | 配列に対して要素ごとの計算を行うループ |
| 事前割り当て | 2–100x | ループ内で配列を拡張している(x = [x; newRow]) |
| 不要な再計算 | 2–50x | 同じコストの高い式を複数回計算している |
discretize/histcounts | 2–50x | データのビニングや分類を行うループ |
| 永続キャッシュ | 1.5–95x | load() の繰り返しやコストの高いオブジェクト生成 |
| 論理インデックス | 1.2–5x | 配列のインデックス指定だけを目的に find() を使用している |
arguments ブロック | 1.1–1.8x | inputParser を使用している関数 |
| 代数的簡略化 | 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 つだけ — 各最適化の後に測定し、効果があった変更を把握してください
- 正しさを検証する — すべての最適化で同等の出力が得られる必要があります
- 1.2 倍のしきい値 — 1.2 倍未満の高速化は、ノイズと確実に区別できません
- GPU の計測 — GPU コードの計測前後には必ず
wait(gpuDevice)を実行してください 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.