mcpField
M
matlab-performance-optimizer

matlab-performance-optimizer

github.com/matlab开发192439 次安装2 周前更新
代码仓库

关于 matlab-performance-optimizer

MATLAB Performance Optimizer 是帮助 MATLAB 开发者定位并优化代码性能的技能指南,涵盖向量化、内存管理、分析和并行计算。它建议先测量瓶颈,再应用优化并复测。

主要功能

  1. 01循环向量化与数组预分配
  2. 02数据类型及稀疏矩阵内存优化
  3. 03使用 profiler 和 timeit 分析
  4. 04并行循环与计算建议
  5. 05MEX、缓存和 JIT 优化方法

适用场景

  1. 01加速运行缓慢的 MATLAB 代码
  2. 02降低大型数据运算的内存占用
  3. 03测量并验证优化前后的性能

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/matlab/agent-skills-playground --skill matlab-performance-optimizer

安装后在 Claude Code 中输入/matlab-performance-optimizer确认已加载。

详细介绍

MATLAB 性能优化器

使用向量化、内存管理和性能分析工具优化 MATLAB 代码性能。

何时使用此技能

  • 优化运行缓慢或效率低下的 MATLAB 代码
  • 将循环转换为向量化运算
  • 减少内存使用量
  • 提升算法性能
  • 用户提到:缓慢、性能、优化、加速、高效、内存
  • 对代码进行性能分析以查找瓶颈
  • 并行化计算

核心优化原则

1. 向量化(最重要)

尽可能用向量化运算替换循环。

较慢——使用循环:

% Slow approach
n = 1000000;
result = zeros(n, 1);
for i = 1:n
    result(i) = sin(i) * cos(i);
end

较快——向量化:

% Fast approach
n = 1000000;
i = (1:n).';
result = sin(i) .* cos(i);
2. 预分配数组

始终在循环前预分配数组。

较慢——逐渐增大数组:

% Very slow - array grows each iteration
result = [];
for i = 1:10000
    result(end+1) = i^2;
end

较快——预分配:

% Fast - preallocated array
n = 10000;
result = zeros(n, 1);
for i = 1:n
    result(i) = i^2;
end
3. 使用内置函数

MATLAB 内置函数经过了高度优化。

较慢——手动实现:

% Slow
sum_val = 0;
for i = 1:length(x)
    sum_val = sum_val + x(i);
end

较快——内置函数:

% Fast
sum_val = sum(x);

向量化技巧

逐元素运算

使用 .*、./、.^ 进行逐元素运算:

% Instead of this:
for i = 1:length(x)
    y(i) = x(i)^2 + 2*x(i) + 1;
end

% Do this:
y = x.^2 + 2*x + 1;
逻辑索引

使用逻辑索引替换条件循环:

% Instead of this:
count = 0;
for i = 1:length(data)
    if data(i) > threshold
        count = count + 1;
        filtered(count) = data(i);
    end
end
filtered = filtered(1:count);

% Do this:
filtered = data(data > threshold);
矩阵运算

使用矩阵乘法替代嵌套循环:

% Instead of this:
C = zeros(size(A, 1), size(B, 2));
for i = 1:size(A, 1)
    for j = 1:size(B, 2)
        for k = 1:size(A, 2)
            C(i,j) = C(i,j) + A(i,k) * B(k,j);
        end
    end
end

% Do this:
C = A * B;
累积运算

使用 cumsum、cumprod、cummax、cummin:

% Instead of this:
running_sum = zeros(size(data));
running_sum(1) = data(1);
for i = 2:length(data)
    running_sum(i) = running_sum(i-1) + data(i);
end

% Do this:
running_sum = cumsum(data);

内存优化

使用合适的数据类型
% Instead of default double (8 bytes)
data = rand(1000, 1000);  % 8 MB

% Use single precision when appropriate (4 bytes)
data = single(rand(1000, 1000));  % 4 MB

% Use integers when applicable
indices = uint32(1:1000000);  % 4 MB instead of 8 MB
稀疏矩阵

对于大部分元素为零的矩阵:

% Dense matrix (wastes memory)
A = zeros(10000, 10000);
A(1:100, 1:100) = rand(100);  % 800 MB

% Sparse matrix (efficient)
A = sparse(10000, 10000);
A(1:100, 1:100) = rand(100);  % Only stores non-zeros
清除未使用的变量
% Process large data
largeData = loadData();
processedData = processData(largeData);

% Clear when no longer needed
clear largeData;

% Continue with processed data
results = analyze(processedData);
原地运算
% Instead of creating copies
A = A + 5;  % In-place when possible

% Avoid unnecessary copies
B = A;      % Creates copy if A is modified later
B = A + 0;  % Forces copy

性能分析与基准测试

使用性能分析器
% Profile code execution
profile on
myFunction(inputs);
profile viewer
profile off

性能分析器会显示:

  • 每个函数所花费的时间
  • 每个函数的调用次数
  • 耗时最长的代码行
时间比较
% Time single execution
tic;
result = myFunction(data);
elapsedTime = toc;

% Benchmark with timeit (more accurate)
timeit(@() myFunction(data))

% Compare multiple approaches
time1 = timeit(@() approach1(data));
time2 = timeit(@() approach2(data));
fprintf('Approach 1: %.6f s\nApproach 2: %.6f s\n', time1, time2);

常见优化模式

模式 1:用逻辑索引替换 find
% SLOW
indices = find(x > 5);
y = x(indices);

% FAST
y = x(x > 5);
模式 2:使用隐式扩展替代 repmat
% SLOW - repmat to match dimensions
A = rand(1000, 5);
B = rand(1, 5);
C = A - repmat(B, size(A, 1), 1);

% FAST - implicit expansion (R2016b+)
C = A - B;
模式 3:避免重复计算
% SLOW - recalculates each iteration
for i = 1:n
    result(i) = data(i) / sqrt(sum(data.^2));
end

% FAST - calculate once
norm_factor = sqrt(sum(data.^2));
for i = 1:n
    result(i) = data(i) / norm_factor;
end

% EVEN FASTER - vectorize
result = data / sqrt(sum(data.^2));
模式 4:高效的字符串运算
% SLOW - concatenating in loop
str = '';
for i = 1:1000
    str = [str, sprintf('Line %d\n', i)];
end

% FAST - cell array + join
lines = cell(1000, 1);
for i = 1:1000
    lines{i} = sprintf('Line %d', i);
end
str = strjoin(lines, '\n');

% FASTEST - vectorized sprintf
str = sprintf('Line %d\n', 1:1000);
模式 5:使用 table 处理混合数据类型
% Instead of separate arrays
names = cell(1000, 1);
ages = zeros(1000, 1);
scores = zeros(1000, 1);

% Use table
data = table(names, ages, scores);
% Faster access and better organization

特定算法的优化

卷积与滤波
% Use built-in functions
filtered = conv(signal, kernel, 'same');
filtered = filter(b, a, signal);

% For 2D
filtered = conv2(image, kernel, 'same');
filtered = imfilter(image, kernel);

% FFT-based for large kernels (zero-pad for linear convolution)
nfft = length(signal) + length(kernel) - 1;
filtered = ifft(fft(signal, nfft) .* fft(kernel, nfft));
距离计算
% Instead of nested loops for pairwise distances
% SLOW
n = size(points, 1);
distances = zeros(n, n);
for i = 1:n
    for j = 1:n
        distances(i,j) = norm(points(i,:) - points(j,:));
    end
end

% FAST - vectorized
distances = pdist2(points, points);
排序与搜索
% Presort for multiple searches
sortedData = sort(data);

% Binary search on sorted data
idx = find(sortedData >= value, 1, 'first');

% Use ismember for set operations
[isPresent, locations] = ismember(searchValues, data);

% Use unique for removing duplicates
uniqueData = unique(data);

并行计算

简单并行循环(parfor)
% Convert for to parfor for independent iterations
parfor i = 1:n
    results(i) = expensiveFunction(data(i));
end

parfor 的要求:

  • 各次迭代必须相互独立
  • 循环变量必须是连续整数
  • 变量必须归类为循环、切片、广播或归约变量
并行数组运算
% Create parallel pool
parpool('local', 4);  % 4 workers

% Use parfeval for asynchronous parallel execution
futures = parfeval(@expensiveFunction, 1, data);
result = fetchOutputs(futures);

% GPU arrays for massive parallelization
gpuData = gpuArray(data);
result = arrayfun(@myFunction, gpuData);
result = gather(result);  % Bring back to CPU

高级优化

使用 MEX 函数处理关键代码段

将性能关键代码转换为 C/C++:

% Create MEX file for bottleneck function
% Write myFunction.c, then compile:
% mex myFunction.c

% Call like regular MATLAB function
result = myFunction(inputs);
使用持久变量缓存结果
function result = expensiveComputation(input)
    persistent cachedData cachedInput

    if isequal(input, cachedInput)
        % Return cached result
        result = cachedData;
        return;
    end

    % Compute and cache
    result = computeExpensiveOperation(input);
    cachedData = result;
    cachedInput = input;
end
JIT 加速最佳实践

MATLAB 的 JIT(即时)编译器会优化:

  • 使用标量运算的简单 for 循环
  • 不含动态特性的函数

适合 JIT 的代码:

function result = jitFriendly(n)
    result = 0;
    for i = 1:n
        result = result + i;
    end
end

不适合 JIT 的代码(应避免):

function result = jitUnfriendly(n)
    result = 0;
    for i = 1:n
        eval(['x' num2str(i) ' = i;']);  % Dynamic code
    end
end

性能检查清单

完成优化代码前,请确认:

  • 尽可能对循环进行向量化
  • 在循环前预分配数组
  • 使用内置函数,而非手动实现
  • 使用逻辑索引,而非 find + 索引
  • 使用合适的数据类型(single 与 double、整数)
  • 对稀疏数据使用稀疏矩阵
  • 将重复计算移到循环外
  • 使用高效方法进行字符串拼接
  • 对代码进行性能分析,找出实际瓶颈
  • 使用矩阵运算替代逐元素循环
  • 考虑对独立运算使用并行计算
  • 优化占用大量内存的运算
  • 对重复且开销大的调用实施缓存

性能分析工作流

  1. 先测量:优化前先进行性能分析

    profile on
    myScript;
    profile viewer
    
  2. 识别瓶颈:重点关注耗时最长的函数

  3. 优化:应用合适的技术

  4. 再次测量:验证改进效果

    % Before
    time_before = timeit(@() myFunction(data));
    
    % After optimization
    time_after = timeit(@() myFunctionOptimized(data));
    
    fprintf('Speedup: %.2fx\n', time_before/time_after);
    
  5. 迭代:针对剩余瓶颈重复上述步骤

常见性能陷阱

陷阱 1:过早优化
  • 先进行性能分析,再进行优化
  • 关注实际瓶颈,而非主观假设
陷阱 2:过度向量化
  • 有时循环更清晰,而且速度足够快
  • 在可读性和性能之间取得平衡
陷阱 3:忽略内存访问模式
% SLOW - inner loop over columns (row-major traversal in column-major MATLAB)
for i = 1:rows
    for j = 1:cols
        A(i,j) = process(i, j);
    end
end

% FAST - inner loop over rows (column-major traversal, contiguous memory)
for j = 1:cols
    for i = 1:rows
        A(i,j) = process(i, j);
    end
end

% FASTEST - vectorized
[I, J] = ndgrid(1:rows, 1:cols);
A = process(I, J);
陷阱 4:不必要的数据类型转换
% SLOW - repeated conversions
for i = 1:n
    x = double(data(i));
    result(i) = sin(x);
end

% FAST - convert once
x = double(data);
result = sin(x);

优化示例

示例 1:图像处理
% SLOW
[rows, cols] = size(image);
output = zeros(rows, cols);
for i = 2:rows-1
    for j = 2:cols-1
        output(i,j) = mean(image(i-1:i+1, j-1:j+1), 'all');
    end
end

% FAST
kernel = ones(3,3) / 9;
output = conv2(image, kernel, 'same');
示例 2:统计分析
% SLOW
n = size(data, 1);
means = zeros(n, 1);
for i = 1:n
    means(i) = mean(data(i, :));
end

% FAST
means = mean(data, 2);
示例 3:时间序列处理
% SLOW
n = length(signal);
movingAvg = zeros(size(signal));
window = 10;
for i = window:n
    movingAvg(i) = mean(signal(i-window+1:i));
end

% FAST - trailing window: [window-1 past samples, 0 future samples]
movingAvg = movmean(signal, [window-1 0]);

性能问题排查

问题:向量化后代码仍然很慢

  • 解决方案:通过性能分析查找新的瓶颈;考虑算法复杂度

问题:内存不足错误

  • 解决方案:使用较小的数据类型,分块处理,使用稀疏矩阵

问题:parfor 比 for 循环慢

  • 解决方案:检查开销是否超过收益;确保迭代任务足够耗时

问题:GPU 计算比 CPU 慢

  • 解决方案:数据传输开销可能超过计算耗时;对大型数组使用 GPU

更多资源

  • 使用 profile viewer 分析性能
  • 使用 memory 检查内存用量
  • 使用 doc 查询:timeit、tic/toc、parfor、gpuArray、sparse
  • 查看 MATLAB 性能和内存文档

评论

支持 Markdown