Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Analyze Simulink Profiler results to find simulation bottlenecks or compare two profiler sessions to identify regressions. Use when asked to profile a Simulink model, analyze profiler data, find what is slow, or compare simulation performance between two runs or releases.
.claude/skills/hashgraph-online-simulink-profiler-analyzer/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 94% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 94% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 68% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 63% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 67% | 0% |
You are an expert at analyzing Simulink Profiler data. You help users identify simulation bottlenecks in a single profiler session, or compare two sessions to pinpoint performance regressions.
Simulink.profiler.Data into structured tables (phases, block profiles, execution tree)Before any analysis, run the setup function located in the skill's scripts/ 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.
matlabrun('SCRIPTS_FOLDER/setup.m')
Replace SCRIPTS_FOLDER with the absolute path to this skill's scripts/ directory (derived from the <skill_files> entries below — use the parent folder of any listed .m file).
This makes the following functions available:
parseSimulinkProfilerData — parse Simulink.profiler.Data into structured tablesdisplayBlockHotspots — display top N block-level hotspotsdisplayExecTreeHotspots — display top N execution-tree hotspotsdrillIntoSubsystem — filter exec tree to a specific subsystemcomparePhases — compare phase-level timing between two sessionscompareBlockProfiles — compare block-level timing between two sessionscompareExecNodes — compare exec-tree nodes for a subsystem across sessionsgenerateProfilerReport — generate a self-contained HTML report with findingsUse when the user wants to profile a model that is loaded or can be loaded in MATLAB.
matlab% Load the model if not already open load_system('ModelName'); % Enable the profiler and simulate set_param('ModelName', 'Profile', 'on'); simOut = sim('ModelName'); % Extract profiler data profilerData = Simulink.profiler.Data(simOut);
After obtaining profilerData, proceed to the Analysis Workflow.
Use when the user provides a .mat file containing saved profiler results. The variable inside is typically named profilerData but may vary.
matlabd = load('path/to/profilerData.mat'); % Inspect variable names disp(fieldnames(d)); % Use the Simulink.profiler.Data variable (name may vary) profilerData = d.profilerData;
If the user has a profilerData variable already in the MATLAB workspace, use it directly.
The user may state that a variable like profilerData already exists in the workspace. Verify with whos profilerData and use it directly.
matlabresults = parseSimulinkProfilerData(profilerData);
This returns a struct with:
results.modelName — run identifier stringresults.totalSimTime — total wall-clock time in secondsresults.phases — table of top-level phases (compile, init, simulation, termination)results.blockProfiles — table of per-block timing from the UI node treeresults.execTree — table of all execution nodes flattened from the exec treeDisplay the phases table to understand where time is spent at the highest level:
matlabfprintf('Model: %s\nTotal time: %.2f s\n\n', results.modelName, results.totalSimTime); disp(results.phases);
Report which phase dominates (compile, simulation, initialization, or termination).
matlabdisplayBlockHotspots(results.blockProfiles); % top 20 by default displayBlockHotspots(results.blockProfiles, 10); % or specify N
Identify blocks with high SelfTime_s — these are the actual compute bottlenecks. Blocks with high TotalTime_s but low SelfTime_s are containers whose children consume the time.
matlabdisplayExecTreeHotspots(results.execTree); % top 20 by default displayExecTreeHotspots(results.execTree, 10); % or specify N
This also shows per-call cost (selfTime / numberOfCalls) for each node.
Key execution methods to watch for:
ModelReference.Outputs.Major — model reference output computation per stepStateflowChild.Outputs.Major — Stateflow / MATLAB Function block executionScope.SetupRunTimeResources — scope initialization overheadS-Function.SetupRunTimeResources — S-function initializationDataStoreRead.Outputs.Major — data store access overhead.Update — block state update costWhen a subsystem or model reference is identified as slow, use:
matlabdrillIntoSubsystem(results.execTree, "SubsystemName"); drillIntoSubsystem(results.execTree, "SubsystemName", 0.01); % custom threshold
Adjust the self-time threshold based on the model's total time. For large models, use a higher threshold.
Summarize the findings in a structured format:
Generate a self-contained HTML report with all profiling data plus the findings and recommendations from Step 6. Build the findings string using Markdown-style formatting, then call generateProfilerReport:
matlabfindings = sprintf([ ... '## Key Findings\n' ... '- Simulation phase dominates at 95%% of total time\n' ... '- Scope blocks consume 2.3 s of init time\n' ... '\n' ... '## Recommendations\n' ... '- Disable or close all Scope blocks for batch runs\n' ... '- Switch model references to Accelerator mode\n']); generateProfilerReport(results, findings); generateProfilerReport(results, findings, 'MyReport.html'); % custom output path
The report includes:
When comparing two profiler sessions (e.g., different releases, before/after a change):
matlabr1 = parseSimulinkProfilerData(profilerData1); r2 = parseSimulinkProfilerData(profilerData2);
matlabcomparePhases(r1, r2); % default labels comparePhases(r1, r2, "R2023b", "R2025b"); % custom labels comparePhases(r1, r2, "Before", "After"); % or any labels
matlabcompareBlockProfiles(r1, r2); % top 20, default labels compareBlockProfiles(r1, r2, 10, "Before", "After"); % top 10, custom labels
When a specific subsystem is identified as regressed, compare its internal exec nodes:
matlabcompareExecNodes(r1, r2, "SubsystemName"); compareExecNodes(r1, r2, "SubsystemName", 0.01, "R2023b", "R2025b");
Summarize:
ModelReference.Outputs.Major entry with selfTime == totalTime. No internal detail is visible. A high self time here indicates overhead in the accelerated model reference execution engine, not in any specific block.mdlStart.Always compute per-call cost when comparing: selfTime / numberOfCalls. A block may have high total time simply because it is called many times (e.g., in a triggered or enabled subsystem). The displayExecTreeHotspots and drillIntoSubsystem functions include per-call cost automatically.
parseSimulinkProfilerData to parse data — never manually traverse the tree.fprintf loops.SelfTime_s descending to find actual compute bottlenecks, or by TotalTime_s descending to find the most time-consuming subtrees.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-08 | pass→pass | 16,027 | 11,243 | -30% | 1 | 1 | 0% | 2,425 | 4,685 | +93% | 0 | 0 | — |
case-01 | fail→fail | 7,094 | 93,496 | +1218% | 1 | 1 | 0% | 312 | 3,090 | +890% | 0 | 0 | — |
case-02 | fail→fail | 23,006 | 7,836 | -66% | 1 | 1 | 0% | 3,689 | 3,169 | -14% | 0 | 0 | — |
case-03 | fail→fail | 29,002 | 24,243 | -16% | 1 | 1 | 0% | 4,443 | 2,950 | -34% | 0 | 0 | — |
case-04 | pass→pass | 16,591 | 16,781 | +1% | 1 | 1 | 0% | 3,023 | 5,904 | +95% | 0 | 0 | — |
case-05 | pass→pass | 22,542 | 27,770 | +23% | 1 | 1 | 0% | 2,564 | 5,612 | +119% | 0 | 0 | — |
case-06 | pass→pass | 23,516 | 19,677 | -16% | 1 | 1 | 0% | 3,346 | 6,785 | +103% | 0 | 0 | — |
case-07 | pass→pass | 18,098 | 13,796 | -24% | 1 | 1 | 0% | 2,134 | 4,143 | +94% | 0 | 0 | — |
case-09 | fail→pass | 20,218 | 16,060 | -21% | 1 | 1 | 0% | 2,552 | 4,943 | +94% | 0 | 0 | — |
case-10 | fail→pass | 17,887 | 15,476 | -13% | 1 | 1 | 0% | 2,149 | 4,166 | +94% | 0 | 0 | — |
case-11 | pass→pass | 19,037 | 10,961 | -42% | 1 | 1 | 0% | 2,214 | 4,373 | +98% | 0 | 0 | — |
case-12 | pass→pass | 21,676 | 11,502 | -47% | 1 | 1 | 0% | 2,516 | 4,306 | +71% | 0 | 0 | — |
case-13 | fail→pass | 31,040 | 19,057 | -39% | 1 | 1 | 0% | 2,364 | 3,966 | +68% | 0 | 0 | — |
case-14 | fail→pass | 21,008 | 11,742 | -44% | 1 | 1 | 0% | 2,378 | 3,880 | +63% | 0 | 0 | — |
case-15 | fail→pass | 26,729 | 10,398 | -61% | 1 | 1 | 0% | 2,168 | 3,621 | +67% | 0 | 0 | — |
case-16 | fail→fail | 13,023 | 8,068 | -38% | 1 | 1 | 0% | 566 | 2,920 | +416% | 0 | 0 | — |
case-17 | fail→pass | 22,121 | 6,830 | -69% | 1 | 1 | 0% | 2,432 | 3,896 | +60% | 0 | 0 | — |
case-18 | pass→pass | 20,786 | 10,798 | -48% | 1 | 1 | 0% | 2,490 | 3,481 | +40% | 0 | 0 | — |
case-19 | fail→pass | 35,847 | 3,681 | -90% | 1 | 1 | 0% | 5,725 | 3,327 | -42% | 0 | 0 | — |
case-20 | pass→pass | 36,075 | 9,350 | -74% | 1 | 1 | 0% | 1,840 | 4,176 | +127% | 0 | 0 | — |
case-21 | fail→pass | 18,433 | 9,529 | -48% | 1 | 1 | 0% | 2,107 | 4,331 | +106% | 0 | 0 | — |
case-22 | pass→pass | 11,645 | 13,935 | +20% | 1 | 1 | 0% | 1,773 | 4,236 | +139% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 19 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +36 percentage points is the difference between those two pass rates over the 19 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.