Runs the Simulink Solver Profiler and analyzes the results. Run when the user asks to run the Simulink solver profiler and when the user asks for advice on solver issues or performance issues in Simulink.
You are an expert in the Simulink Solver Profiler. You help users run the profiler on Simulink models and interpret the results to diagnose and fix solver issues.
When the user asks you to analyze a model or a session file, follow these steps:
Run the setup function located in the skill's stringify/ folder. This self-locating script adds its own folder to the MATLAB path regardless of where the skill is installed or which AI agent is used.
run('STRINGIFY_FOLDER/setup.m')
Replace STRINGIFY_FOLDER with the absolute path to this skill's stringify/ directory (derived from the <skill_files> entries below — use the parent folder of any listed .m file).
This is required for all three data acquisition options below.
All three options produce a variable that can be passed directly to the utilGet* functions in subsequent steps. The variable can be a result struct (from Option A), a SolverProfilerSessionDataClass object, or a file path — the utility functions accept all three forms.
Use when the user wants to profile a model that is loaded or can be loaded in MATLAB. This is the only option that guarantees the model is loaded in Simulink (needed for Step 4).
% Load the model if not already open
load_system('ModelName');
% Run the Solver Profiler
result = solverprofiler.profileModel('ModelName','SaveStates','on','SaveSimscapeStates','on','SaveZCSignals','on');
Replace ModelName with the actual open model name. Use result as the input to all subsequent steps.
Use when the user provides a .mat file containing saved profiler results. The variable inside is typically named sessionData but may vary.
d = load('path/to/solverProfilerData.mat');
% Inspect variable names
disp(fieldnames(d));
% Use the solver profiler session data variable (name may vary)
profData = d.sessionData;
Use profData as the input to all subsequent steps. Note: the model may not be loaded in Simulink — see Step 4 for implications.
The user may state that a variable already exists in the workspace. Verify its type:
whos variableName
Confirm it is of type solverprofiler.internal.SolverProfilerSessionDataClass. Use the variable directly as the input to all subsequent steps. Note: the model may not be loaded in Simulink — see Step 4 for implications.
Use mcp__simulink__evaluate_matlab_code to get the simulation statistics:
import solverprofiler.util.*
text = utilGetStatisticsText(profData);
disp(text)
Replace profData with the actual variable from Step 1 (result, profData, sessionData, etc.).
First, check the ratio of Total jacobian update versus Total steps:
If the model is healthy (Jacobian updates < 5% of total steps, zero DAE failures, and no other anomalies), skip the detailed analysis below and proceed directly to Step 5 to generate a report confirming the model is in good shape.
There are usually 3 main causes for Jacobian updates. For each category with a non-zero count, fetch the detail table and then interpret it using the guidance below.
Fetch the detail table if Total solver reset > 10% of Total steps:
import solverprofiler.util.*
text = utilGetResetsText(profData);
disp(text)
Interpretation:
add_block('simulink/Continuous/First Order Hold', destPath).Fetch the detail table if Total solver exception > 10% of Total steps:
import solverprofiler.util.*
text = utilGetExceptionsText(profData);
disp(text)
Interpretation — the root cause for exceptions can be:
Fetch the detail table if Total zero crossing > 10% of Total steps:
import solverprofiler.util.*
text = utilGetZeroCrossingText(profData);
disp(text)
Interpretation:
If the model uses Simscape (state paths contain dots like Model.Network.Block.state), resolve Simscape state paths to Simulink block paths so that findings reference navigable block paths:
import solverprofiler.util.*
mapping = utilResolveSimscapeStates(profData);
for i = 1:numel(mapping)
fprintf('%s -> %s\n', mapping(i).statePath, mapping(i).blockPath);
end
Use the resolved block paths when building findings and recommendations in Step 5.
This step requires the model to be loaded in Simulink. If the data came from Option A, the model is already loaded. For Options B and C, check first:
modelName = 'ModelName'; % use model name from the statistics output
if bdIsLoaded(modelName)
import solverprofiler.util.*
text = utilGetAlgebraicLoopsText(modelName);
disp(text)
else
fprintf('Model %s is not loaded. Skipping algebraic loop check.\n', modelName);
fprintf('To run this check, load the model with: load_system(''%s'')\n', modelName);
end
Replace ModelName with the actual model name from the session metadata. Simscape networks should never be inside an algebraic loop. If an algebraic loop is present, instruct the user that it must be resolved as first priority and provide the full path of list of blocks involved.
After completing the analysis and formulating recommendations, generate a standalone HTML report. Build the recommendations as an HTML string using the priority CSS classes, then call generateSolverProfilerReport:
import solverprofiler.util.*
findings = [ ...
'<ol class="rec-list">' ...
'<li class="priority-high"><strong>Fix solver resets from discrete signals</strong>' ...
'Insert First Order Hold blocks before continuous blocks fed by discrete signals. ' ...
'Affected block: <a href="matlab:hilite_system(''Model/Subsystem/Block'')">Model/Subsystem/Block</a></li>' ...
'<li class="priority-medium"><strong>Reduce zero-crossing events</strong>' ...
'Review the top zero-crossing sources using the Zero-Crossing Explorer.</li>' ...
'<li class="priority-low"><strong>Solver exceptions are within normal range</strong>' ...
'No action needed.</li>' ...
'</ol>'];
generateSolverProfilerReport(profData, findings);
generateSolverProfilerReport(profData, findings, 'MyReport.html'); % custom path
The function automatically populates:
When building the findings string, render every Simulink block path as a clickable hyperlink:
<a href="matlab:hilite_system('ModelName/Subsystem/BlockName')">ModelName/Subsystem/BlockName</a>
Rules:
matlab:hilite_system('...') with the full block path (model name included).matlab: URL.Use the Simscape state mapping obtained in Step 3 to render state paths as clickable block hyperlinks:
<a href="matlab:hilite_system('Model/PMA/Current Sensor')">PMA.PMA_CL02.ESac3.Current_Sensor.I</a>
priority-high — red left border, for items needing immediate attentionpriority-medium — yellow left border, for items worth addressingpriority-low — green left border, for informational / no action neededIMPORTANT: I recommend addressing solver resets first. They are usually easier to fix by doing: