Conversation
There was a problem hiding this comment.
Pull request overview
Adds support in the OpenVINO EP to dump OpenVINO profiling (perf count) information to a directory specified by the ORT_OPENVINO_PERF_COUNT environment variable when profiling is enabled on the compiled model.
Changes:
- Make
IBackend::Infernon-const and updateBasicBackendaccordingly. - Add
ORT_OPENVINO_PERF_COUNTenv var plumbing and write perf counts to a CSV file under the specified directory. - Simplify
printPerformanceCountsAPIs and change output format to CSV.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| onnxruntime/core/providers/openvino/ibackend.h | Adjust Infer interface constness to support new inference-time behavior. |
| onnxruntime/core/providers/openvino/backends/basic_backend.h | Update Infer override signature to match interface change. |
| onnxruntime/core/providers/openvino/backends/basic_backend.cc | Implement perf-count CSV dumping to an env-var directory after inference when profiling is enabled. |
| onnxruntime/core/providers/openvino/backend_utils.h | Add env-var helper and update perf-count printing function signatures. |
| onnxruntime/core/providers/openvino/backend_utils.cc | Implement env-var helper and update perf-count printing implementation/output format. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| std::filesystem::create_directory(dir, ec); | ||
| if (ec) { | ||
| LOGS_DEFAULT(INFO) << log_tag << ec.message(); | ||
| return; | ||
| } else { | ||
| std::string filestring = subgraph_context_.subgraph_name.substr(std::string("OpenVINOExecutionProvider_OpenVINO-EP").length()) + "_perf_count.csv"; | ||
| std::filesystem::path filename(session_context_.GetModelPath().stem().string() + filestring); | ||
| filename = dir / filename; | ||
| std::ofstream out(filename); | ||
| if (out.is_open()) { | ||
| printPerformanceCounts(infer_request, out); | ||
| out.close(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Using std::filesystem::create_directory(dir, ec) will fail for nested paths (e.g., /tmp/a/b) and doesn’t verify that an existing path is actually a directory. Consider using create_directories and/or checking exists(dir) + is_directory(dir) so ORT_OPENVINO_PERF_COUNT can point to a deeper dump directory reliably.
| std::filesystem::create_directory(dir, ec); | |
| if (ec) { | |
| LOGS_DEFAULT(INFO) << log_tag << ec.message(); | |
| return; | |
| } else { | |
| std::string filestring = subgraph_context_.subgraph_name.substr(std::string("OpenVINOExecutionProvider_OpenVINO-EP").length()) + "_perf_count.csv"; | |
| std::filesystem::path filename(session_context_.GetModelPath().stem().string() + filestring); | |
| filename = dir / filename; | |
| std::ofstream out(filename); | |
| if (out.is_open()) { | |
| printPerformanceCounts(infer_request, out); | |
| out.close(); | |
| } | |
| } | |
| // Ensure the performance count path exists and is a directory. | |
| bool exists = std::filesystem::exists(dir, ec); | |
| if (ec) { | |
| LOGS_DEFAULT(INFO) << log_tag << "Failed to check existence of perf count path '" << dir.string() << "': " << ec.message(); | |
| return; | |
| } | |
| if (exists) { | |
| bool is_dir = std::filesystem::is_directory(dir, ec); | |
| if (ec || !is_dir) { | |
| LOGS_DEFAULT(INFO) << log_tag << "Perf count path '" << dir.string() << "' exists but is not a directory."; | |
| return; | |
| } | |
| } else { | |
| std::filesystem::create_directories(dir, ec); | |
| if (ec) { | |
| LOGS_DEFAULT(INFO) << log_tag << "Failed to create perf count directory '" << dir.string() << "': " << ec.message(); | |
| return; | |
| } | |
| } | |
| std::string filestring = subgraph_context_.subgraph_name.substr(std::string("OpenVINOExecutionProvider_OpenVINO-EP").length()) + "_perf_count.csv"; | |
| std::filesystem::path filename(session_context_.GetModelPath().stem().string() + filestring); | |
| filename = dir / filename; | |
| std::ofstream out(filename); | |
| if (out.is_open()) { | |
| printPerformanceCounts(infer_request, out); | |
| out.close(); | |
| } |
| std::filesystem::path filename(session_context_.GetModelPath().stem().string() + filestring); | ||
| filename = dir / filename; | ||
| std::ofstream out(filename); | ||
| if (out.is_open()) { | ||
| printPerformanceCounts(infer_request, out); | ||
| out.close(); | ||
| } |
There was a problem hiding this comment.
This writes to a deterministic filename per model/subgraph on every inference. Since ORT sessions can run concurrently, multiple threads can race and truncate/overwrite the same CSV, producing corrupt output. Please make the output path unique per inference (e.g., include PID/TID/timestamp/request counter) or guard file writing with a mutex; also log when ofstream fails to open so failures aren’t silent.
| @@ -72,6 +72,8 @@ namespace backend_utils { | |||
|
|
|||
| bool IsDebugEnabled(); | |||
|
|
|||
There was a problem hiding this comment.
IsPerfCountEnabled() returns a string path (not a boolean) so the name is misleading. Consider renaming to something like GetPerfCountDumpDir()/GetPerfCountDumpPath() to better communicate the contract to callers.
| // Returns the path where performance counts are dumped when enabled. | |
| std::string GetPerfCountDumpPath(); | |
| [[deprecated("IsPerfCountEnabled() is misleadingly named; use GetPerfCountDumpPath() instead.")]] |
| } | ||
|
|
||
| std::string IsPerfCountEnabled() { | ||
| std::string env_name = onnxruntime::GetEnvironmentVar("ORT_OPENVINO_PERF_COUNT"); |
There was a problem hiding this comment.
IsPerfCountEnabled() re-reads the environment variable on every call, unlike the other helpers in this file that cache via static std::string. Since this is called from the inference path, please cache the value (and reuse the same static pattern) to avoid repeated getenv/alloc work per inference.
| std::string env_name = onnxruntime::GetEnvironmentVar("ORT_OPENVINO_PERF_COUNT"); | |
| static std::string env_name = onnxruntime::GetEnvironmentVar("ORT_OPENVINO_PERF_COUNT"); |
| LOGS_DEFAULT(INFO) << log_tag << ec.message(); | ||
| return; | ||
| } else { | ||
| std::string filestring = subgraph_context_.subgraph_name.substr(std::string("OpenVINOExecutionProvider_OpenVINO-EP").length()) + "_perf_count.csv"; |
There was a problem hiding this comment.
subgraph_context_.subgraph_name.substr(std::string("OpenVINOExecutionProvider_OpenVINO-EP").length()) can throw std::out_of_range if the subgraph name doesn't start with that exact prefix (e.g., OpenVINO subgraph names elsewhere are OpenVINO-EP-subgraph_N). Please guard this with a prefix check (or avoid hardcoding the prefix) so dumping perf counts can’t crash inference.
| std::string filestring = subgraph_context_.subgraph_name.substr(std::string("OpenVINOExecutionProvider_OpenVINO-EP").length()) + "_perf_count.csv"; | |
| const std::string prefix = "OpenVINOExecutionProvider_OpenVINO-EP"; | |
| std::string subgraph_suffix; | |
| if (subgraph_context_.subgraph_name.size() >= prefix.size() && | |
| subgraph_context_.subgraph_name.compare(0, prefix.size(), prefix) == 0) { | |
| subgraph_suffix = subgraph_context_.subgraph_name.substr(prefix.size()); | |
| } else { | |
| // Fallback: use the full subgraph name if it does not start with the expected prefix | |
| subgraph_suffix = subgraph_context_.subgraph_name; | |
| } | |
| std::string filestring = subgraph_suffix + "_perf_count.csv"; |
| } | ||
|
|
||
| std::string IsPerfCountEnabled() { | ||
| std::string env_name = onnxruntime::GetEnvironmentVar("ORT_OPENVINO_PERF_COUNT"); |
There was a problem hiding this comment.
Use GetEnvironmentVariableA as GetEnvironmentVar might create env creation conflicts on Windows.
Refer PR - https://github.com/intel-innersource/frameworks.ai.onnxruntime.openvino-plugin-ep/pull/182
Description
https://jira.devtools.intel.com/browse/EISW-195635
This change allows profiling information to be dumped to a Directory defined by environment variable
ORT_OPENVINO_PERF_COUNT when Perf Count Property is enabled.
Motivation and Context
https://jira.devtools.intel.com/browse/EISW-195635
Compiler team has requested for profiling information