ronantakizawa/codereview-bench huggingface dataset:
Repository: microsoft/onnxruntime
File: onnxruntime/test/testdata/input_propagated_to_output.py (Python)

Code before:
"""
Run this script to recreate the original onnx model.
Example usage:
python input_propagated_to_output.py input_propagated_to_output.onnx
"""

import os
import sys

import numpy as np
import onnx
from onnx import TensorProto, helper, numpy_helper

DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "input_propagated_to_output")


def order_repeated_field(repeated_proto, key_name, order):
    order = list(order)
    repeated_proto.sort(key=lambda x: order.index(getattr(x, key_name)))


def make_node(op_type, inputs, outputs, name=None, doc_string=None, domain=None, **kwargs):
    node = helper.make_node(op_type, inputs, outputs, name, doc_string, domain, **kwargs)
    if doc_string == "":
        node.doc_string = ""
    order_repeated_field(node.attribute, "name", kwargs.keys())

Review comment (suggestion):
Note: I tried to use the [onnx2py](https://github.com/microsoft/onnxconverter-common/blob/master/onnxconverter_common/onnx2py.py) tool to create this script from the model, but it threw some errors. So, I created this script manually.

Code after:
"""
Run this script to recreate the original onnx model.
Example usage:
python input_propagated_to_output.py input_propagated_to_output.onnx
"""

import sys

import numpy as np
import onnx


def order_repeated_field(repeated_proto, key_name, order):
    order = list(order)
    repeated_proto.sort(key=lambda x: order.index(getattr(x, key_name)))


def make_node(op_type, inputs, outputs, name=None, doc_string=None, domain=None, **kwargs):
    node = onnx.helper.make_node(op_type, inputs, outputs, name, doc_string, domain, **kwargs)
    if doc_string == "":
        node.doc_string = ""
    order_repeated_field(node.attribute, "name", kwargs.keys())
    return node


def make_graph(*args, doc_string=None, **kwargs):
Repository: microsoft/onnxruntime
File: onnxruntime/core/platform/linux/device_discovery.cc (C++)

Code before:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/platform/device_discovery.h"
#include "core/framework/ortdevice.h"

#include <filesystem>
#include <fstream>
#include <iterator>
#include <optional>
#include <string>
#include <string_view>

#include "core/common/common.h"
#include "core/common/logging/logging.h"
#include "core/common/parse_string.h"
#include "core/common/string_utils.h"

namespace fs = std::filesystem;

namespace onnxruntime {

namespace {

Status ErrorCodeToStatus(const std::error_code& ec) {
  if (!ec) {
    return Status::OK();
  }

  return Status{common::StatusCategory::ONNXRUNTIME, common::StatusCode::FAIL,

Review comment (refactor):
usually, we want to stick to this dependency ordering:

https://github.com/microsoft/onnxruntime/blob/5ef8ce2103e862a1c14166ed7a406f88b990927e/cmake/onnxruntime.cmake#L238-L254

so onnxruntime_common (which contains core/platform/linux/device_discovery.cc) should not depend on onnxruntime_framework (core/framework/ortdevice.h).

we can move the vendor id enum and helper function to be a separate header, in onnxruntime_common perhaps, or just move the helper function to this file for now. 

Code after:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/platform/device_discovery.h"

#include <filesystem>
#include <fstream>
#include <iterator>
#include <optional>
#include <regex>
#include <string_view>

#include "core/common/common.h"
#include "core/common/logging/logging.h"
#include "core/common/parse_string.h"
#include "core/common/string_utils.h"

namespace fs = std::filesystem;

namespace onnxruntime {

namespace {

Status ErrorCodeToStatus(const std::error_code& ec) {
  if (!ec) {
    return Status::OK();
  }

  return Status{common::StatusCategory::ONNXRUNTIME, common::StatusCode::FAIL,
                MakeString("Error: std::error_code with category name: ", ec.category().name(),
Repository: microsoft/onnxruntime
File: onnxruntime/core/providers/webnn/builders/impl/scatterElements_op_builder.cc (C++)

Code before:
  const auto& updates = *node.InputDefs()[2];

  int32_t data_type;
  int32_t indices_type;
  int32_t updates_type;
  if (!GetType(data, data_type, logger) || !GetType(indices, indices_type, logger) ||
      !GetType(updates, updates_type, logger)) {
    return false;
  }

  if (data_type != updates_type) {
    return false;
  }

  const std::string_view op_type = node.OpType();

  if (!IsDataTypeSupportedByOp(op_type, data_type, wnn_limits, "input", "data", logger) ||
      !IsInputRankSupportedByOp(node, wnn_limits, logger)) {
    return false;
  }

  // ONNX specifies that indices must use int64, but some WebNN backends only support int32.
  // Allows to use int32 as a workaround for such backends.
  can_fallback_int64_to_int32_ = CanFallbackInt64ToInt32(wnn_limits, "scatterElements", "indices");
  return IsDataTypeSupportedByOp(op_type, indices_type, wnn_limits, "indices", "indices", logger) ||
         can_fallback_int64_to_int32_;
}

void CreateScatterElementsOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) {
  op_registrations.builders.push_back(std::make_unique<ScatterElementsOpBuilder>());
  op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get());
}

}  // namespace webnn
}  // namespace onnxruntime


Review comment (suggestion):
```c++
  return can_fallback_int64_to_int32_ ||
      IsDataTypeSupportedByOp(op_type, indices_type, wnn_limits, "indices", "indices", logger);
```
Suggest reversing the test, since `can_fallback_int64_to_int32_` already checked some data type support, that might skip the `IsDataTypeSupportedByOp` call.

Code after:
  const auto& updates = *node.InputDefs()[2];

  int32_t data_type;
  int32_t indices_type;
  int32_t updates_type;
  if (!GetType(data, data_type, logger) || !GetType(indices, indices_type, logger) ||
      !GetType(updates, updates_type, logger)) {
    return false;
  }

  if (data_type != updates_type) {
    return false;
  }

  const std::string_view op_type = node.OpType();

  if (!IsDataTypeSupportedByOp(op_type, data_type, wnn_limits, "input", "data", logger) ||
      !IsInputRankSupportedByOp(node, wnn_limits, logger)) {
    return false;
  }

  // ONNX specifies that indices must use int64, but some WebNN backends only support int32.
  // Allows to use int32 as a workaround for such backends.
  can_fallback_int64_to_int32_ = CanFallbackInt64ToInt32(wnn_limits, "scatterElements", "indices");
  return can_fallback_int64_to_int32_ ||
         IsDataTypeSupportedByOp(op_type, indices_type, wnn_limits, "indices", "indices", logger);
}

void CreateScatterElementsOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) {
  op_registrations.builders.push_back(std::make_unique<ScatterElementsOpBuilder>());
  op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get());
}

}  // namespace webnn
}  // namespace onnxruntime
Repository: microsoft/onnxruntime
File: js/node/src/ort_singleton_data.h (C/C++)

Code before:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include <napi.h>
#include "onnxruntime_cxx_api.h"

/**
 * The OrtSingletonData class is designed to manage the lifecycle of necessary singleton instance data, including:
 *
 * - The Ort::Env singleton instance.
 *   This is a global singleton that is shared across all InferenceSessionWrap instances. It is created when the first
 *   time `InferenceSession.initOrtOnce()` is called.
 *
 * - The Ort::RunOptions singleton instance.
 *   This is an empty default RunOptions instance. It is created once to allow reuse across all session inference runs.
 *
 * The OrtSingletonData class uses the "Meyers Singleton" pattern to ensure thread-safe lazy initialization, as well as
 * proper destruction order at program exit.
 */
struct OrtSingletonData {
  struct OrtObjects {
    std::unique_ptr<Ort::Env> env;
    std::unique_ptr<Ort::RunOptions> default_run_options;

   private:
    // The following pattern ensures that OrtObjects can only be created by OrtSingletonData
    OrtObjects(int log_level);
    friend struct OrtSingletonData;
  };

  static OrtObjects& GetOrCreateOrtObjects(int log_level = ORT_LOGGING_LEVEL_WARNING);

  // Get the global Ort::Env
  static const Ort::Env* Env();

  // Get the default Ort::RunOptions
  static const Ort::RunOptions* DefaultRunOptions();
};


Review comment (suggestion):
You may use Ort::Env directly, since Ort::Env essentially is a unique_ptr.  It has a "release()" function which works a bit different than unique_ptr's release() function, but it can be used to serve your needs. 


Code after:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include <napi.h>
#include "onnxruntime_cxx_api.h"

/**
 * The OrtSingletonData class is designed to manage the lifecycle of necessary singleton instance data, including:
 *
 * - The Ort::Env singleton instance.
 *   This is a global singleton that is shared across all InferenceSessionWrap instances. It is created when the first
 *   time `InferenceSession.initOrtOnce()` is called.
 *
 * - The Ort::RunOptions singleton instance.
 *   This is an empty default RunOptions instance. It is created once to allow reuse across all session inference runs.
 *
 * The OrtSingletonData class uses the "Meyers Singleton" pattern to ensure thread-safe lazy initialization, as well as
 * proper destruction order at program exit.
 */
struct OrtSingletonData {
  struct OrtObjects {
    Ort::Env env;
    Ort::RunOptions default_run_options;

   private:
    // The following pattern ensures that OrtObjects can only be created by OrtSingletonData
    OrtObjects(int log_level);
    friend struct OrtSingletonData;
  };

  static OrtObjects& GetOrCreateOrtObjects(int log_level = ORT_LOGGING_LEVEL_WARNING);

  // Get the global Ort::Env
  static const Ort::Env& Env();

  // Get the default Ort::RunOptions
  static const Ort::RunOptions& DefaultRunOptions();
};
Repository: microsoft/onnxruntime
File: onnxruntime/core/common/cpuid_info_vendor.cc (C++)

Code before:
const CpuVendorInfo* FindCpuVendorInfo(cpuinfo_vendor vendor) {
  const auto vendor_mapping_it = std::find_if(kCpuVendorInfos.begin(), kCpuVendorInfos.end(),
                                              [vendor](const CpuVendorInfo& entry) {
                                                return entry.vendor == vendor;
                                              });

  if (vendor_mapping_it != kCpuVendorInfos.end()) {
    return &*vendor_mapping_it;
  }

  return nullptr;
}

}  // namespace

void CPUIDInfo::VendorInfoInit() {
  const cpuinfo_vendor vendor = [&]() {
    cpuinfo_vendor result = cpuinfo_vendor_unknown;
#if defined(CPUINFO_SUPPORTED)
    if (pytorch_cpuinfo_init_) {
      const auto* processor = cpuinfo_get_processor(0);
      if (processor && processor->core) {
        result = processor->core->vendor;
      }
    }
#endif  // defined(CPUINFO_SUPPORTED)
#if defined(_AIX)
    result = kIBMCpuVendorInfo.vendor;
#endif
    return result;
  }();

  const auto* vendor_info = FindCpuVendorInfo(vendor);
  if (vendor_info == nullptr) {
    LogEarlyWarning(MakeString("Unknown CPU vendor. cpuinfo_vendor value: ", static_cast<int>(vendor)));
    vendor_info = &kUnknownCpuVendorInfo;
  }

  vendor_ = vendor_info->name;
  vendor_id_ = vendor_info->id;
}

}  // namespace onnxruntime


Review comment (suggestion):
```suggestion
#else
#if defined(_AIX)
    result = cpuinfo_vendor_ibm;
#endif
#endif
```

and then we also don't need to define `kIBMCpuVendorInfo` above.

Code after:
                                                return entry.vendor == vendor;
                                              });

  if (vendor_mapping_it != kCpuVendorInfos.end()) {
    return &*vendor_mapping_it;
  }

  return nullptr;
}

}  // namespace

void CPUIDInfo::VendorInfoInit() {
  const cpuinfo_vendor vendor = [&]() {
    cpuinfo_vendor result = cpuinfo_vendor_unknown;
#if defined(CPUINFO_SUPPORTED)
    if (pytorch_cpuinfo_init_) {
      const auto* processor = cpuinfo_get_processor(0);
      if (processor && processor->core) {
        result = processor->core->vendor;
      }
    }
#endif  // defined(CPUINFO_SUPPORTED)
#if defined(_AIX)
    result = cpuinfo_vendor_ibm;
#endif
    return result;
  }();

  const auto* vendor_info = FindCpuVendorInfo(vendor);
  if (vendor_info == nullptr) {
    LogEarlyWarning(MakeString("Unknown CPU vendor. cpuinfo_vendor value: ", static_cast<int>(vendor)));
    vendor_info = &kUnknownCpuVendorInfo;
  }

  vendor_ = vendor_info->name;
  vendor_id_ = vendor_info->id;
}

}  // namespace onnxruntime
Repository: microsoft/onnxruntime
File: onnxruntime/core/mlas/lib/qgemm.cpp (C++)

Code before:
            ThreadsPerGemm = ptrdiff_t(M);
        }

        WorkBlock.ThreadCountM = ThreadsPerGemm;
        WorkBlock.ThreadCountN = 1;
    }
    TargetThreadCount = ThreadsPerGemm * BatchN;

    MlasTrySimpleParallel(ThreadPool, TargetThreadCount, [&](ptrdiff_t tid) {
        const auto gemm_i = tid / ThreadsPerGemm;
        const auto blk_i = tid % ThreadsPerGemm;
        MlasGemmQuantThreaded(&WorkBlock, &Shape, &DataParams[gemm_i], blk_i);
    });
}

bool
MLASCALL
MlasIsDynamicQGemmAvailable()
{
#if defined(USE_KLEIDIAI) && !defined(_MSC_VER)
  return ArmKleidiAI::UseSME2;
#else
  return false;
#endif
}

void
MLASCALL
MlasDynamicQGemmBatch (
    const MLAS_GEMM_DYN_QUANT_SHAPE_PARAMS& Shape,
    const MLAS_GEMM_DYN_QUANT_DATA_PARAMS* DataParams,
    const size_t BatchN,
    MLAS_THREADPOOL* ThreadPool
) {
#if defined(USE_KLEIDIAI) && !defined(_MSC_VER)
    //No fallback
    ArmKleidiAI::MlasDynamicQGemmBatch(Shape, DataParams, BatchN, ThreadPool);
#endif

    MLAS_UNREFERENCED_PARAMETER(Shape);
    MLAS_UNREFERENCED_PARAMETER(DataParams);
    MLAS_UNREFERENCED_PARAMETER(BatchN);
    MLAS_UNREFERENCED_PARAMETER(ThreadPool);
}

int32_t
MlasSymmQgemmGetKernelOutputCnt()
{
    const MLAS_SYMM_QGEMM_DISPATCH* dispatch = GetMlasPlatform().SymmQgemmDispatch;
    return int32_t(dispatch->StrideM);
}

Review comment (suggestion):
removing `if (SME2)` here because the expectation is that this will only be called if `MlasIsDynamicQGemmAvailable()` returns true.

Code after:
            ThreadsPerGemm = ptrdiff_t(M);
        }

        WorkBlock.ThreadCountM = ThreadsPerGemm;
        WorkBlock.ThreadCountN = 1;
    }
    TargetThreadCount = ThreadsPerGemm * BatchN;

    MlasTrySimpleParallel(ThreadPool, TargetThreadCount, [&](ptrdiff_t tid) {
        const auto gemm_i = tid / ThreadsPerGemm;
        const auto blk_i = tid % ThreadsPerGemm;
        MlasGemmQuantThreaded(&WorkBlock, &Shape, &DataParams[gemm_i], blk_i);
    });
}

bool
MLASCALL
MlasIsDynamicQGemmAvailable()
{
#if defined(USE_KLEIDIAI) && !defined(_MSC_VER)
  return ArmKleidiAI::UseSME2;
#else
  return false;
#endif
}

void
MLASCALL
MlasDynamicQGemmBatch (
    const MLAS_GEMM_DYN_QUANT_SHAPE_PARAMS& Shape,
    const MLAS_GEMM_DYN_QUANT_DATA_PARAMS* DataParams,
    const size_t BatchN,
    MLAS_THREADPOOL* ThreadPool
) {
    assert(MlasIsDynamicQGemmAvailable());

#if defined(USE_KLEIDIAI) && !defined(_MSC_VER)
    //No fallback
    ArmKleidiAI::MlasDynamicQGemmBatch(Shape, DataParams, BatchN, ThreadPool);
#endif

    MLAS_UNREFERENCED_PARAMETER(Shape);
    MLAS_UNREFERENCED_PARAMETER(DataParams);
    MLAS_UNREFERENCED_PARAMETER(BatchN);
    MLAS_UNREFERENCED_PARAMETER(ThreadPool);
}

int32_t
MlasSymmQgemmGetKernelOutputCnt()
{
    const MLAS_SYMM_QGEMM_DISPATCH* dispatch = GetMlasPlatform().SymmQgemmDispatch;
Repository: microsoft/onnxruntime
File: onnxruntime/core/mlas/lib/sconv_nchw_kernel_neon.cpp (C++)

Code before:
    acc += row[base + 1] * w1;
    acc += row[base + 2] * w2;
    return acc;
}

MLAS_FORCEINLINE void DepthwiseAccumulateRowVector(
    float32x4_t& acc,
    const float* row,
    size_t base,
    float w0,
    float w1,
    float w2
)
{
    if (row == nullptr) {
        return;
    }

    const float* r = row + base;
    const float32x4_t c0 = vld1q_f32(r);
    const float32x4_t c1 = vld1q_f32(r + 1);
    const float32x4_t c2 = vld1q_f32(r + 2);

    acc = vmlaq_n_f32(acc, c0, w0);
    acc = vmlaq_n_f32(acc, c1, w1);
    acc = vmlaq_n_f32(acc, c2, w2);
}

MLAS_FORCEINLINE float DepthwiseComputeEdge(
    const float* row0,
    const float* row1,
    const float* row2,
    ptrdiff_t iw,
    size_t width,
    const float w00,
    const float w01,
    const float w02,
    const float w10,
    const float w11,
    const float w12,
    const float w20,
    const float w21,
    const float w22
)
{
    float acc = 0.0f;
    const ptrdiff_t c0 = iw;
    const ptrdiff_t c1 = iw + 1;
    const ptrdiff_t c2 = iw + 2;

    acc += DepthwiseSampleValue(row0, c0, width) * w00;

Review comment (suggestion):
Consider using `MlasLoadFloat32x4` & `MlasMultiplyAddFloat32x4`? The latter has an overloaded implementation for a scalar multiplier as well. 

And in other parts of the file, you can use `MlasZeroFloat32x4` & `MlasStoreFloat32x4`

Code after:
    acc += row[base + 1] * w1;
    acc += row[base + 2] * w2;
    return acc;
}

MLAS_FORCEINLINE void DepthwiseAccumulateRowVector(
    float32x4_t& acc,
    const float* row,
    size_t base,
    float w0,
    float w1,
    float w2
)
{
    if (row == nullptr) {
        return;
    }

    const float* r = row + base;
    const float32x4_t c0 = MlasLoadFloat32x4(r);
    const float32x4_t c1 = MlasLoadFloat32x4(r + 1);
    const float32x4_t c2 = MlasLoadFloat32x4(r + 2);

    acc = MlasMultiplyAddFloat32x4(c0, w0, acc);
    acc = MlasMultiplyAddFloat32x4(c1, w1, acc);
    acc = MlasMultiplyAddFloat32x4(c2, w2, acc);
}

MLAS_FORCEINLINE float DepthwiseComputeEdge(
    const float* row0,
    const float* row1,
    const float* row2,
    ptrdiff_t iw,
    size_t width,
    const float w00,
    const float w01,
    const float w02,
    const float w10,
    const float w11,
    const float w12,
    const float w20,
    const float w21,
    const float w22
)
{
    float acc = 0.0f;
    const ptrdiff_t c0 = iw;
    const ptrdiff_t c1 = iw + 1;
    const ptrdiff_t c2 = iw + 2;

    acc += DepthwiseSampleValue(row0, c0, width) * w00;
Repository: microsoft/onnxruntime
File: onnxruntime/core/mlas/lib/qgemm.cpp (C++)

Code before:

    } else {

        if (size_t(ThreadsPerGemm) > M) {
            ThreadsPerGemm = ptrdiff_t(M);
        }

        WorkBlock.ThreadCountM = ThreadsPerGemm;
        WorkBlock.ThreadCountN = 1;
    }
    TargetThreadCount = ThreadsPerGemm * BatchN;

    MlasTrySimpleParallel(ThreadPool, TargetThreadCount, [&](ptrdiff_t tid) {
        const auto gemm_i = tid / ThreadsPerGemm;
        const auto blk_i = tid % ThreadsPerGemm;
        MlasGemmQuantThreaded(&WorkBlock, &Shape, &DataParams[gemm_i], blk_i);
    });
}

bool
MLASCALL
MlasIsDynamicQGemmAvailable()
{
#if defined(USE_KLEIDIAI)
  if(ArmKleidiAI::UseSME2) {
    return ArmKleidiAI::UseSME2;
  }
  else {
    return ArmKleidiAI::UseSME;
  }

#else
  return false;
#endif
}

void
MLASCALL
MlasDynamicQGemmBatch (
    const MLAS_GEMM_DYN_QUANT_SHAPE_PARAMS& Shape,
    const MLAS_GEMM_DYN_QUANT_DATA_PARAMS* DataParams,
    const size_t BatchN,
    MLAS_THREADPOOL* ThreadPool
) {
    assert(MlasIsDynamicQGemmAvailable());

#if defined(USE_KLEIDIAI)
    //No fallback
    ArmKleidiAI::MlasDynamicQGemmBatch(Shape, DataParams, BatchN, ThreadPool);
#endif


Review comment (suggestion):
This has a change in behavior in that we are allowing SME1 kernels to run now when previously we only used to run SME2. Have you vetted this on an SME1 machine ? For the short term, I propose, returning true if `ArmKleidiAI::UseSME2` || `ArmKleidiAI::vendor_name.compare("Qualcomm") == 0` if ENABLE_QMX_KERNELS if ON.

Code after:

    } else {

        if (size_t(ThreadsPerGemm) > M) {
            ThreadsPerGemm = ptrdiff_t(M);
        }

        WorkBlock.ThreadCountM = ThreadsPerGemm;
        WorkBlock.ThreadCountN = 1;
    }
    TargetThreadCount = ThreadsPerGemm * BatchN;

    MlasTrySimpleParallel(ThreadPool, TargetThreadCount, [&](ptrdiff_t tid) {
        const auto gemm_i = tid / ThreadsPerGemm;
        const auto blk_i = tid % ThreadsPerGemm;
        MlasGemmQuantThreaded(&WorkBlock, &Shape, &DataParams[gemm_i], blk_i);
    });
}

bool
MLASCALL
MlasIsDynamicQGemmAvailable()
{
#if defined(USE_KLEIDIAI)
  return (ArmKleidiAI::UseSME2 || ArmKleidiAI::UseSME);
#else
  return false;
#endif
}

void
MLASCALL
MlasDynamicQGemmBatch (
    const MLAS_GEMM_DYN_QUANT_SHAPE_PARAMS& Shape,
    const MLAS_GEMM_DYN_QUANT_DATA_PARAMS* DataParams,
    const size_t BatchN,
    MLAS_THREADPOOL* ThreadPool
) {
    assert(MlasIsDynamicQGemmAvailable());

#if defined(USE_KLEIDIAI)
    //No fallback
    ArmKleidiAI::MlasDynamicQGemmBatch(Shape, DataParams, BatchN, ThreadPool);
#endif

    MLAS_UNREFERENCED_PARAMETER(Shape);
    MLAS_UNREFERENCED_PARAMETER(DataParams);
    MLAS_UNREFERENCED_PARAMETER(BatchN);
    MLAS_UNREFERENCED_PARAMETER(ThreadPool);
}
Repository: microsoft/onnxruntime
File: onnxruntime/core/providers/webgpu/webgpu_execution_provider.cc (C++)

Code before:
  }
#endif  // ENABLE_PIX_FOR_WEBGPU_EP

  if (context_.ValidationMode() >= ValidationMode::Basic) {
    return context_.PopErrorScope();
  } else {
    return Status::OK();
  }
}

bool WebGpuExecutionProvider::IsGraphCaptureEnabled() const {
  return enable_graph_capture_;
}

bool WebGpuExecutionProvider::IsGraphCaptured(int graph_annotation_id) const {
  return is_graph_captured_ && graph_annotation_id != -1;
}

Status WebGpuExecutionProvider::ReplayGraph(int graph_annotation_id) {
  ORT_ENFORCE(IsGraphCaptured(graph_annotation_id));
  if (profiler_->Enabled()) {
    context_.StartProfiling();
  }
  context_.Replay(captured_commands_, *graph_buffer_mgr_);
  if (profiler_->Enabled()) {
    context_.CollectProfilingData(profiler_->Events());
  }
  return Status::OK();
}

webgpu::BufferManager& WebGpuExecutionProvider::BufferManager() const {
  if (graph_buffer_mgr_) {
    return *graph_buffer_mgr_;
  } else {
    return context_.BufferManager();
  }
}

bool WebGpuExecutionProvider::IsGraphCaptureAllowed() const {
  return regular_run_count_before_graph_capture_ >= min_num_runs_before_cuda_graph_capture_;
}

void WebGpuExecutionProvider::IncrementRegularRunCountBeforeGraphCapture() {
  ++regular_run_count_before_graph_capture_;
}
}  // namespace onnxruntime


Review comment (suggestion):
As you know, I deleted the parameter in`CollectProfilingData()`, so this needs special attention here.

Code after:
  }

  return Status::OK();
}

Status WebGpuExecutionProvider::OnRunEnd(bool /* sync_stream */, const onnxruntime::RunOptions& run_options) {
  context_.Flush(BufferManager());

  if (IsGraphCaptureEnabled() && !IsGraphCaptured(m_current_graph_annotation_id)) {
    if (m_current_graph_annotation_id != -1 && IsGraphCaptureAllowed()) {
      context_.CaptureEnd();
      is_graph_captured_ = true;
      ORT_RETURN_IF_ERROR(ReplayGraph(m_current_graph_annotation_id));
    } else {
      IncrementRegularRunCountBeforeGraphCapture();
    }
  }

  if ((session_profiler_ && session_profiler_->Enabled()) || run_options.enable_profiling) {
    context_.CollectProfilingData();
  }

#if defined(ENABLE_PIX_FOR_WEBGPU_EP)
  if (pix_frame_generator_) {
    pix_frame_generator_->GeneratePIXFrame();
  }
#endif  // ENABLE_PIX_FOR_WEBGPU_EP

  if (context_.ValidationMode() >= ValidationMode::Basic) {
    return context_.PopErrorScope();
  } else {
    return Status::OK();
  }
}

bool WebGpuExecutionProvider::IsGraphCaptureEnabled() const {
  return enable_graph_capture_;
}

bool WebGpuExecutionProvider::IsGraphCaptured(int graph_annotation_id) const {
  return is_graph_captured_ && graph_annotation_id != -1;
}

Status WebGpuExecutionProvider::ReplayGraph(int graph_annotation_id) {
  ORT_ENFORCE(IsGraphCaptured(graph_annotation_id));
  // TODO: enable profiling in run level
  if (session_profiler_ && session_profiler_->Enabled()) {
    context_.StartProfiling();
  }
  context_.Replay(captured_commands_, *graph_buffer_mgr_);
  if (session_profiler_ && session_profiler_->Enabled()) {