Skip to content

Add OpenVINO operator profiling to perf - #1377

Merged
xieofxie merged 8 commits into
mainfrom
hualxie/intel_op
Sep 2, 2026
Merged

Add OpenVINO operator profiling to perf#1377
xieofxie merged 8 commits into
mainfrom
hualxie/intel_op

Conversation

@xieofxie

@xieofxie xieofxie commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add basic OpenVINO operator tracing for CPU and NPU perf runs
  • enable ONNX Runtime profiling and parse detailed OpenVINO child kernel events
  • exclude warmup invocations and report the raw profiling JSON path
  • validate minimum ONNX Runtime and OpenVINO EP profiling support

ORT compatibility

ORT 1.27 validates supplied and default local-function graph attributes even when the function body does not reference or execute them. FP16 conversion now checks those attributes before conversion and rejects captured tensors whose outer binding becomes FP16 while the skipped graph remains FP32. This prevents the Tensor element type mismatch. 10 != 1 session-loading failure and remains compatible with ORT 1.24 by applying the stricter validation conservatively.

@xieofxie
xieofxie requested a review from a team as a code owner September 1, 2026 03:17
Comment thread src/winml/modelkit/session/monitor/openvino_monitor.py
Comment thread src/winml/modelkit/session/monitor/openvino_monitor.py Outdated
@xieofxie
xieofxie merged commit 02138e3 into main Sep 2, 2026
9 checks passed
@xieofxie
xieofxie deleted the hualxie/intel_op branch September 2, 2026 06:31
Comment thread pyproject.toml
# normalized) — an exact `==` can't reconcile the two. A bounded range keeps the
# 1.24.x series while resolving to the published wheel.
"onnxruntime-windowsml>=1.24.5,<1.25 ; sys_platform == 'win32'",
"onnxruntime-windowsml>=1.24.5,<1.28 ; sys_platform == 'win32'",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This range now resolves to ORT 1.27.1, but the pinned windowsml==2.0.300 declares onnxruntime-windowsml==1.24.5.202604171637 as its matching runtime; windowsml==2.3.42 is the package paired with ORT 1.27.1. Please update the WindowsML package in lockstep rather than installing a mismatched WinML C API/runtime pair.

self._device = normalized_device
self._output_dir = Path(output_dir) if output_dir is not None else Path.cwd()
self._output_dir.mkdir(parents=True, exist_ok=True)
self._profile_prefix = (self._output_dir / "onnxruntime_profile").resolve()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make this prefix unique per monitor? output_dir is normally the save directory or cwd, and ORT only appends a millisecond timestamp. Overlapping perf processes can therefore create the same filename or have _find_fresh_profile() select the other process's newer profile. A per-run UUID in the prefix would keep discovery scoped to this trace.


def configure_session_options(self, session_options: ort.SessionOptions) -> None:
"""Enable ORT profiling on the monitored inference session."""
session_options.enable_profiling = True

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an NPU session, ORT OpenVINO 1.27.1 explicitly falls back to OV CPU when compilation fails unless session.disable_cpu_ep_fallback is set. Because that fallback stays inside OpenVINOExecutionProvider, these events still pass the parser and are returned as status="ok", device="npu" even though they are CPU timings. Please disable this fallback for NPU profiling or validate/report the actual OV device.

tracing_backend="onnxruntime",
num_samples=self._measured_iterations
or max(operator.sample_count for operator in operators),
summary={"accel_execute_us": total_us},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accel_execute_us is a per-inference mean in the existing basic/QNN schema, but total_us sums every retained run. The added 4 us / 6 us test therefore displays 10 us, and this value grows with --iterations even when latency is unchanged. Please compute the mean of the per-inference accelerator totals here.

if self._measured_iterations is not None
else None
)
retained[parent_name] = occurrences[self._warmup_iterations : stop]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These occurrences are partition executions, not necessarily top-level inference runs. A partition inside Loop or Scan can execute multiple times per inference, so this slice removes only the first loop execution from the warmup and can retain the rest of the warmup as measured samples. Please group spans by their enclosing inference run before applying the warmup/sample window.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants