已开启
feat(profiler): add CPU-to-NPU correlation for ACLprof #46050
denis_g创建于 9月8日
feat(profiler): add CPU-to-NPU correlation for ACLprof #46050
已开启
共 17 个文件变更+2605-77
| @@ -416,7 +416,7 @@ if (DEFINED BUILD_FXRT) | |||
| 416 | add_subdirectory(${PROJECT_SOURCE_DIR}/fxrt/fxrt) | 416 | add_subdirectory(${PROJECT_SOURCE_DIR}/fxrt/fxrt) |
| 417 | endif() | 417 | endif() |
| 418 | 418 | ||
| 419 | -if (DEFINED BUILD_GTEST) | 419 | +if (BUILD_GTEST) |
| 420 | enable_testing() | 420 | enable_testing() |
| 421 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build/gtest) | 421 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build/gtest) |
| 422 | add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/googletest) | 422 | add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/googletest) |
| @@ -426,8 +426,20 @@ if (DEFINED BUILD_GTEST) | |||
| 426 | add_subdirectory(${PROJECT_SOURCE_DIR}/test/cpp/api) | 426 | add_subdirectory(${PROJECT_SOURCE_DIR}/test/cpp/api) |
| 427 | add_executable(test_api ${TORCH_API_TEST_SOURCES}) | 427 | add_executable(test_api ${TORCH_API_TEST_SOURCES}) |
| 428 | 428 | ||
| 429 | + find_path(KINETO_TEST_INCLUDE_DIR ActivityBuffers.h | ||
| 430 | + HINTS "${PYTORCH_INSTALL_DIR}/include/kineto" | ||
| 431 | + NO_DEFAULT_PATH | ||
| 432 | + DOC "Kineto internal headers matching installed PyTorch (libkineto/src)") | ||
| 433 | + if(NOT EXISTS "${KINETO_TEST_INCLUDE_DIR}/ActivityBuffers.h") | ||
| 434 | + message(FATAL_ERROR | ||
| 435 | + "test_api requires ActivityBuffers.h. Set KINETO_TEST_INCLUDE_DIR to " | ||
| 436 | + "libkineto/src from the Kineto version used to build installed PyTorch.") | ||
| 437 | + endif() | ||
| 438 | + target_include_directories(test_api PRIVATE "${KINETO_TEST_INCLUDE_DIR}") | ||
| 439 | + target_compile_definitions(test_api PRIVATE KINETO_NAMESPACE=libkineto) | ||
| 440 | + | ||
| 429 | target_link_libraries(test_api PUBLIC torch_npu) | 441 | target_link_libraries(test_api PUBLIC torch_npu) |
| 430 | - target_link_libraries(test_api PUBLIC gtest_main gtest) | 442 | + target_link_libraries(test_api PUBLIC gtest_main gtest gmock) |
| 431 | endif() | 443 | endif() |
| 432 | 444 | ||
| 433 | if (DEFINED BUILD_LIBTORCH) | 445 | if (DEFINED BUILD_LIBTORCH) |
| @@ -1,2 +1,5 @@ | |||
| 1 | set(TORCH_API_TEST_DIR "${PROJECT_SOURCE_DIR}/test/cpp/api") | 1 | set(TORCH_API_TEST_DIR "${PROJECT_SOURCE_DIR}/test/cpp/api") |
| 2 | -set(TORCH_API_TEST_SOURCES ${TORCH_API_TEST_DIR}/modules.cpp PARENT_SCOPE) | 2 | +set(TORCH_API_TEST_SOURCES |
| 3 | + ${TORCH_API_TEST_DIR}/modules.cpp | ||
| 4 | + ${TORCH_API_TEST_DIR}/profiler.cpp | ||
| 5 | + PARENT_SCOPE) | ||
| @@ -1,16 +1,107 @@ | |||
| 1 | +import json | ||
| 2 | +import pickle | ||
| 1 | import unittest | 3 | import unittest |
| 2 | -from unittest.mock import patch | 4 | +from unittest.mock import PropertyMock, patch |
| 3 | 5 | ||
| 6 | +from torch._C._profiler import _ExperimentalConfig as KinetoExperimentalConfig | ||
| 7 | +from torch_npu.profiler import _NPUExperimentalConfig | ||
| 4 | from torch_npu.profiler.experimental_config import supported_ai_core_metrics | 8 | from torch_npu.profiler.experimental_config import supported_ai_core_metrics |
| 5 | from torch_npu.profiler.experimental_config import supported_profiler_level | 9 | from torch_npu.profiler.experimental_config import supported_profiler_level |
| 6 | from torch_npu.profiler.experimental_config import supported_export_type | 10 | from torch_npu.profiler.experimental_config import supported_export_type |
| 7 | from torch_npu.profiler.experimental_config import _ExperimentalConfig | 11 | from torch_npu.profiler.experimental_config import _ExperimentalConfig |
| 12 | +from torch_npu.profiler.experimental_config import ExportType, ProfilerLevel | ||
| 8 | from torch_npu._C._profiler import _ExperimentalConfig as Cpp_ExperimentalConfig | 13 | from torch_npu._C._profiler import _ExperimentalConfig as Cpp_ExperimentalConfig |
| 9 | from torch_npu.testing.testcase import TestCase, run_tests | 14 | from torch_npu.testing.testcase import TestCase, run_tests |
| 10 | from torch_npu.profiler.analysis.prof_common_func._constant import Constant | 15 | from torch_npu.profiler.analysis.prof_common_func._constant import Constant |
| 11 | from torch_npu.profiler.analysis.prof_common_func._cann_package_manager import CannPackageManager | 16 | from torch_npu.profiler.analysis.prof_common_func._cann_package_manager import CannPackageManager |
| 12 | 17 | ||
| 13 | 18 | ||
| 19 | +class TestNPUExperimentalConfig(unittest.TestCase): | ||
| 20 | + def test_backend_only_compatibility(self): | ||
| 21 | + self.assertEqual(str(_NPUExperimentalConfig()), '{"backend":"mspti"}') | ||
| 22 | + for backend in ["mspti", "aclprof", "invalid", None, 1]: | ||
| 23 | + with self.subTest(backend=backend): | ||
| 24 | + config = _NPUExperimentalConfig(backend=backend) | ||
| 25 | + self.assertEqual(str(config), json.dumps({"backend": backend}, separators=(",", ":"))) | ||
| 26 | + self.assertEqual(config.__getstate__(), KinetoExperimentalConfig( | ||
| 27 | + custom_profiler_config=str(config)).__getstate__()) | ||
| 28 | + | ||
| 29 | + def test_configuration_combinations(self): | ||
| 30 | + for backend in [None, "mspti", "aclprof"]: | ||
| 31 | + for options in [{"profiler_level": ProfilerLevel.Level1}, {"export_type": ExportType.Db}, | ||
| 32 | + {"profiler_level": ProfilerLevel.Level1, "export_type": [ExportType.Db]}]: | ||
| 33 | + with self.subTest(backend=backend, options=options): | ||
| 34 | + kwargs = {} if backend is None else {"backend": backend} | ||
| 35 | + data = json.loads(str(_NPUExperimentalConfig(**kwargs, **options))) | ||
| 36 | + expected = {"backend": backend or "mspti", **options} | ||
| 37 | + if "export_type" in options: | ||
| 38 | + expected["export_type"] = [ExportType.Db] | ||
| 39 | + self.assertEqual(data, expected) | ||
| 40 | + | ||
| 41 | + def test_supported_levels(self): | ||
| 42 | + for level in supported_profiler_level(): | ||
| 43 | + with self.subTest(level=level): | ||
| 44 | + self.assertEqual(json.loads(str(_NPUExperimentalConfig(profiler_level=level)))["profiler_level"], level) | ||
| 45 | + | ||
| 46 | + def test_export_normalization_and_determinism(self): | ||
| 47 | + scalar = _NPUExperimentalConfig(export_type=ExportType.Db) | ||
| 48 | + self.assertEqual(str(scalar), str(_NPUExperimentalConfig(export_type=[ExportType.Db]))) | ||
| 49 | + exports = [ExportType.Text, ExportType.Db, ExportType.Text] | ||
| 50 | + config = _NPUExperimentalConfig(export_type=exports) | ||
| 51 | + self.assertEqual(str(config), '{"backend":"mspti","export_type":["db","text"]}') | ||
| 52 | + exports.clear() | ||
| 53 | + self.assertEqual(str(config), str(_NPUExperimentalConfig(export_type=[ExportType.Db, ExportType.Text]))) | ||
| 54 | + self.assertEqual(str(_NPUExperimentalConfig(profiler_level=None, export_type=None)), | ||
| 55 | + str(_NPUExperimentalConfig())) | ||
| 56 | + | ||
| 57 | + def test_invalid_profiler_level(self): | ||
| 58 | + for level in ["invalid", "Level3", "", 1, True, 1.0, [], {}]: | ||
| 59 | + with self.subTest(level=level), self.assertRaisesRegex(ValueError, "profiler_level"): | ||
| 60 | + _NPUExperimentalConfig(profiler_level=level) | ||
| 61 | + | ||
| 62 | + def test_invalid_export_type(self): | ||
| 63 | + for exports in ["invalid", "db,text", "", 1, True, [], {}, (ExportType.Db,), [ExportType.Db, 1], [[]]]: | ||
| 64 | + with self.subTest(exports=exports), self.assertRaisesRegex(ValueError, "export_type"): | ||
| 65 | + _NPUExperimentalConfig(export_type=exports) | ||
| 66 | + | ||
| 67 | + def test_standard_channel_and_pickle_roundtrip(self): | ||
| 68 | + config = _NPUExperimentalConfig(backend="aclprof", profiler_level=ProfilerLevel.Level1, | ||
| 69 | + export_type=ExportType.Db, verbose=True) | ||
| 70 | + payload = str(config) | ||
| 71 | + self.assertEqual(payload, '{"backend":"aclprof","profiler_level":"Level1","export_type":["db"]}') | ||
| 72 | + standard = KinetoExperimentalConfig(custom_profiler_config=payload, verbose=True) | ||
| 73 | + self.assertEqual(config.__getstate__(), standard.__getstate__()) | ||
| 74 | + for value in [config, standard]: | ||
| 75 | + restored = pickle.loads(pickle.dumps(value)) | ||
| 76 | + self.assertEqual(restored.__getstate__(), value.__getstate__()) | ||
| 77 | + self.assertEqual(str(pickle.loads(pickle.dumps(config))), payload) | ||
| 78 | + # Newer PyTorch versions append unrelated fields after the custom config. | ||
| 79 | + with patch.object(_NPUExperimentalConfig, "__getstate__", return_value=(*config.__getstate__(), False, False)): | ||
| 80 | + self.assertEqual(str(config), payload) | ||
| 81 | + | ||
| 82 | + def test_str_uses_direct_attribute_without_serializing(self): | ||
| 83 | + config = _NPUExperimentalConfig() | ||
| 84 | + payload = '{"backend":"aclprof"}' | ||
| 85 | + with patch.object(_NPUExperimentalConfig, "custom_profiler_config", payload, create=True), \ | ||
| 86 | + patch.object(_NPUExperimentalConfig, "__getstate__", side_effect=AssertionError("unexpected fallback")) as state: | ||
| 87 | + self.assertEqual(str(config), payload) | ||
| 88 | + state.assert_not_called() | ||
| 89 | + | ||
| 90 | + def test_str_falls_back_when_attribute_is_unavailable(self): | ||
| 91 | + config = _NPUExperimentalConfig(backend="aclprof") | ||
| 92 | + payload = '{"backend":"aclprof"}' | ||
| 93 | + with patch.object(_NPUExperimentalConfig, "custom_profiler_config", create=True, | ||
| 94 | + new_callable=PropertyMock, side_effect=AttributeError): | ||
| 95 | + with patch.object(_NPUExperimentalConfig, "__getstate__", return_value=config.__getstate__()) as state: | ||
| 96 | + self.assertEqual(str(config), payload) | ||
| 97 | + state.assert_called_once_with() | ||
| 98 | + self.assertEqual(str(pickle.loads(pickle.dumps(config))), payload) | ||
| 99 | + | ||
| 100 | + def test_json_escaping(self): | ||
| 101 | + backend = 'aclprof",\n"profiler_level":"Level2' | ||
| 102 | + self.assertEqual(json.loads(str(_NPUExperimentalConfig(backend=backend))), {"backend": backend}) | ||
| 103 | + | ||
| 104 | + | ||
| 14 | class TestExperimentalConfig(TestCase): | 105 | class TestExperimentalConfig(TestCase): |
| 15 | 106 | ||
| 16 | @classmethod | 107 | @classmethod |
| @@ -47,6 +138,12 @@ class TestExperimentalConfig(TestCase): | |||
| 47 | experimental_config = _ExperimentalConfig() | 138 | experimental_config = _ExperimentalConfig() |
| 48 | self.assertTrue(isinstance(experimental_config(), Cpp_ExperimentalConfig)) | 139 | self.assertTrue(isinstance(experimental_config(), Cpp_ExperimentalConfig)) |
| 49 | 140 | ||
| 141 | + def test_kineto_backend_config(self): | ||
| 142 | + standard_config = pickle.dumps(KinetoExperimentalConfig()) | ||
| 143 | + aclprof_config = pickle.dumps(_NPUExperimentalConfig(backend="aclprof")) | ||
| 144 | + self.assertNotIn(b'{"backend":"aclprof"}', standard_config) | ||
| 145 | + self.assertIn(b'{"backend":"aclprof"}', aclprof_config) | ||
| 146 | + | ||
| 50 | def test_mstx_domain_switches_will_reset_when_msproftx_and_mstx_not_enabled(self): | 147 | def test_mstx_domain_switches_will_reset_when_msproftx_and_mstx_not_enabled(self): |
| 51 | experimental_config = _ExperimentalConfig(msprof_tx=False, | 148 | experimental_config = _ExperimentalConfig(msprof_tx=False, |
| 52 | mstx=False, | 149 | mstx=False, |
| @@ -136,6 +136,7 @@ TORCH_NPU_LOAD_FUNC(aclrtMemset) | |||
| 136 | TORCH_NPU_LOAD_FUNC(aclrtMemsetAsync) | 136 | TORCH_NPU_LOAD_FUNC(aclrtMemsetAsync) |
| 137 | TORCH_NPU_LOAD_FUNC(aclmdlRICaptureThreadExchangeMode) | 137 | TORCH_NPU_LOAD_FUNC(aclmdlRICaptureThreadExchangeMode) |
| 138 | TORCH_NPU_LOAD_FUNC(aclrtGetLogicDevIdByUserDevId) | 138 | TORCH_NPU_LOAD_FUNC(aclrtGetLogicDevIdByUserDevId) |
| 139 | +TORCH_NPU_LOAD_FUNC(aclrtGetPhyDevIdByUserDevId) | ||
| 139 | TORCH_NPU_LOAD_FUNC(aclrtBinaryLoadFromData) | 140 | TORCH_NPU_LOAD_FUNC(aclrtBinaryLoadFromData) |
| 140 | TORCH_NPU_LOAD_FUNC(aclrtBinaryGetFunction) | 141 | TORCH_NPU_LOAD_FUNC(aclrtBinaryGetFunction) |
| 141 | TORCH_NPU_LOAD_FUNC(aclrtBinaryUnLoad) | 142 | TORCH_NPU_LOAD_FUNC(aclrtBinaryUnLoad) |
| @@ -1943,6 +1944,16 @@ aclError AclrtGetLogicDevIdByUserDevId(const int32_t userDevid, int32_t* const l | |||
| 1943 | TORCH_CHECK(func, "Failed to find function aclrtGetLogicDevIdByUserDevId", PTA_ERROR(ErrCode::NOT_FOUND)); | 1944 | TORCH_CHECK(func, "Failed to find function aclrtGetLogicDevIdByUserDevId", PTA_ERROR(ErrCode::NOT_FOUND)); |
| 1944 | return func(userDevid, logicDevId); | 1945 | return func(userDevid, logicDevId); |
| 1945 | } | 1946 | } |
| 1947 | + | ||
| 1948 | +aclError AclrtGetPhyDevIdByUserDevId(const int32_t userDevId, int32_t* const phyDevId) { | ||
| 1949 | + typedef aclError (*AclrtGetPhyDevIdByUserDevId)(const int32_t, int32_t* const); | ||
| 1950 | + static AclrtGetPhyDevIdByUserDevId func = nullptr; | ||
| 1951 | + if (func == nullptr) { | ||
| 1952 | + func = (AclrtGetPhyDevIdByUserDevId)TORCH_NPU_GET_FUNC(aclrtGetPhyDevIdByUserDevId); | ||
| 1953 | + } | ||
| 1954 | + TORCH_CHECK(func, "Failed to find function aclrtGetPhyDevIdByUserDevId", PTA_ERROR(ErrCode::NOT_FOUND)); | ||
| 1955 | + return func(userDevId, phyDevId); | ||
| 1956 | +} | ||
| 1946 | bool IsExistAclrtLaunchKernelWithHostArgs() { | 1957 | bool IsExistAclrtLaunchKernelWithHostArgs() { |
| 1947 | using Func = decltype(&aclrtLaunchKernelWithHostArgs); | 1958 | using Func = decltype(&aclrtLaunchKernelWithHostArgs); |
| 1948 | static Func func = (Func)TORCH_NPU_GET_FUNC(aclrtLaunchKernelWithHostArgs); | 1959 | static Func func = (Func)TORCH_NPU_GET_FUNC(aclrtLaunchKernelWithHostArgs); |
| @@ -442,6 +442,8 @@ aclError AclrtGetDeviceInfo(uint32_t deviceId, aclrtDevAttr attr, int64_t* value | |||
| 442 | 442 | ||
| 443 | aclError AclrtGetLogicDevIdByUserDevId(const int32_t userDevid, int32_t* const logicDevId); | 443 | aclError AclrtGetLogicDevIdByUserDevId(const int32_t userDevid, int32_t* const logicDevId); |
| 444 | 444 | ||
| 445 | +aclError AclrtGetPhyDevIdByUserDevId(const int32_t userDevId, int32_t* const phyDevId); | ||
| 446 | + | ||
| 445 | aclError AclrtMemSet(void* devPtr, size_t maxCount, int32_t value, size_t count); | 447 | aclError AclrtMemSet(void* devPtr, size_t maxCount, int32_t value, size_t count); |
| 446 | 448 | ||
| 447 | aclError AclrtMemSetAsync(void* devPtr, size_t maxCount, int32_t value, size_t count, aclrtStream stream); | 449 | aclError AclrtMemSetAsync(void* devPtr, size_t maxCount, int32_t value, size_t count, aclrtStream stream); |
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "torch_npu/csrc/framework/utils/OpAdapter.h" | 17 | #include "torch_npu/csrc/framework/utils/OpAdapter.h" |
| 18 | #include "torch_npu/csrc/framework/utils/OpPreparation.h" | 18 | #include "torch_npu/csrc/framework/utils/OpPreparation.h" |
| 19 | #ifndef BUILD_LIBTORCH | 19 | #ifndef BUILD_LIBTORCH |
| 20 | +#include "torch_npu/csrc/profiler/aclprof_activity_profiler.h" | ||
| 20 | #include "torch_npu/csrc/profiler/npu_profiler.h" | 21 | #include "torch_npu/csrc/profiler/npu_profiler.h" |
| 21 | #endif | 22 | #endif |
| 22 | 23 | ||
| @@ -275,7 +276,8 @@ void NpuUtils::ProfReportMarkDataToNpuProfiler(uint32_t category, const std::str | |||
| 275 | if (data.empty()) { | 276 | if (data.empty()) { |
| 276 | return; | 277 | return; |
| 277 | } | 278 | } |
| 278 | - if (torch_npu::profiler::profDataReportEnable().load(std::memory_order_relaxed)) { | 279 | + if (torch_npu::profiler::profDataReportEnable().load(std::memory_order_relaxed) || |
| 280 | + torch_npu::profiler::aclprofTaskQueueCaptureEnabled()) { | ||
| 279 | torch_npu::profiler::reportMarkDataToNpuProfiler(category, data, correlation_id); | 281 | torch_npu::profiler::reportMarkDataToNpuProfiler(category, data, correlation_id); |
| 280 | } | 282 | } |
| 281 | } | 283 | } |
| @@ -304,7 +306,8 @@ void NpuUtils::ProfReportMarkDataToNpuProfiler(uint32_t category, void* data, si | |||
| 304 | if (C10_UNLIKELY(!data)) { | 306 | if (C10_UNLIKELY(!data)) { |
| 305 | return; | 307 | return; |
| 306 | } | 308 | } |
| 307 | - if (torch_npu::profiler::profDataReportEnable().load(std::memory_order_relaxed)) { | 309 | + if (torch_npu::profiler::profDataReportEnable().load(std::memory_order_relaxed) || |
| 310 | + torch_npu::profiler::aclprofTaskQueueCaptureEnabled()) { | ||
| 308 | static const std::map<int64_t, DqueueCall> DEQUEUE_CALL_FUNC_MAP{ | 311 | static const std::map<int64_t, DqueueCall> DEQUEUE_CALL_FUNC_MAP{ |
| 309 | {c10_npu::queue::COMPILE_AND_EXECUTE, &DqueueCompileExcute}, | 312 | {c10_npu::queue::COMPILE_AND_EXECUTE, &DqueueCompileExcute}, |
| 310 | {c10_npu::queue::EXECUTE_OPAPI, &DqueueCompileExcuteOpApi}, | 313 | {c10_npu::queue::EXECUTE_OPAPI, &DqueueCompileExcuteOpApi}, |
| @@ -0,0 +1,124 @@ | |||
| 1 | +// Copyright (c) 2026 Huawei Technologies Co., Ltd | ||
| 2 | +// All rights reserved. | ||
| 3 | +// | ||
| 4 | +// Licensed under the BSD 3-Clause License (the "License"); | ||
| 5 | +// you may not use this file except in compliance with the License. | ||
| 6 | +// You may obtain a copy of the License at | ||
| 7 | +// | ||
| 8 | +// https://opensource.org/licenses/BSD-3-Clause | ||
| 9 | +// | ||
| 10 | +// Unless required by applicable law or agreed to in writing, software | ||
| 11 | +// distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | +// See the License for the specific language governing permissions and | ||
| 14 | +// limitations under the License. | ||
| 15 | + | ||
| 16 | +#pragma once | ||
| 17 | + | ||
| 18 | +#include <cstdint> | ||
| 19 | +#include <memory> | ||
| 20 | +#include <mutex> | ||
| 21 | +#include <optional> | ||
| 22 | +#include <set> | ||
| 23 | +#include <string> | ||
| 24 | +#include <unordered_map> | ||
| 25 | +#include <vector> | ||
| 26 | + | ||
| 27 | +#include "torch_npu/csrc/profiler/npu_activity_profiler.h" | ||
| 28 | + | ||
| 29 | +namespace torch_npu { | ||
| 30 | +namespace profiler { | ||
| 31 | + | ||
| 32 | +namespace detail { | ||
| 33 | +struct AclprofApi; | ||
| 34 | +struct AclprofEvent; | ||
| 35 | +} // namespace detail | ||
| 36 | + | ||
| 37 | +class AclprofActivityProfilerTestPeer; | ||
| 38 | + | ||
| 39 | +TORCH_NPU_API bool aclprofTaskQueueCaptureEnabled(); | ||
| 40 | +TORCH_NPU_API void recordAclprofTaskQueueEvent( | ||
| 41 | + uint32_t category, | ||
| 42 | + uint64_t taskQueueCorrelation, | ||
| 43 | + int64_t monotonicTimestampNs, | ||
| 44 | + int64_t pid, | ||
| 45 | + int64_t tid, | ||
| 46 | + const std::string& name); | ||
| 47 | + | ||
| 48 | +class TORCH_NPU_API AclprofActivityProfiler : public NPUActivityProfiler { | ||
| 49 | + public: | ||
| 50 | + explicit AclprofActivityProfiler(std::set<libkineto::ActivityType> activities); | ||
| 51 | + ~AclprofActivityProfiler() override; | ||
| 52 | + | ||
| 53 | + const char* name() const override { | ||
| 54 | + return "aclprof"; | ||
| 55 | + } | ||
| 56 | + void start() override; | ||
| 57 | + void stop() override; | ||
| 58 | + std::vector<std::string> errors() override; | ||
| 59 | + void processTrace(libkineto::ActivityLogger& logger) override; | ||
| 60 | + void processTrace( | ||
| 61 | + libkineto::ActivityLogger& logger, | ||
| 62 | + libkineto::getLinkedActivityCallback getLinkedActivity, | ||
| 63 | + int64_t startTime, | ||
| 64 | + int64_t endTime) override; | ||
| 65 | + std::unique_ptr<libkineto::DeviceInfo> getDeviceInfo() override; | ||
| 66 | + std::vector<libkineto::ResourceInfo> getResourceInfos() override; | ||
| 67 | + std::unique_ptr<libkineto::CpuTraceBuffer> getTraceBuffer() override; | ||
| 68 | + void pushCorrelationId(uint64_t id) override; | ||
| 69 | + void popCorrelationId() override; | ||
| 70 | + | ||
| 71 | + private: | ||
| 72 | + struct TaskQueueMark { | ||
| 73 | + uint32_t category; | ||
| 74 | + uint64_t taskQueueCorrelation; | ||
| 75 | + int64_t timestampNs; | ||
| 76 | + int64_t tid; | ||
| 77 | + std::string name; | ||
| 78 | + std::optional<int32_t> kinetoCorrelation; | ||
| 79 | + }; | ||
| 80 | + | ||
| 81 | + AclprofActivityProfiler(std::set<libkineto::ActivityType> activities, std::shared_ptr<detail::AclprofApi> api); | ||
| 82 | + bool finishCollection(bool reportErrors); | ||
| 83 | + void cleanup(); | ||
| 84 | + void resetCorrelationState(); | ||
| 85 | + void beginCorrelationCapture(); | ||
| 86 | + void endCorrelationCapture(); | ||
| 87 | + void recordTaskQueueEvent( | ||
| 88 | + uint32_t category, | ||
| 89 | + uint64_t taskQueueCorrelation, | ||
| 90 | + int64_t monotonicTimestampNs, | ||
| 91 | + int64_t pid, | ||
| 92 | + int64_t tid, | ||
| 93 | + const std::string& name); | ||
| 94 | + void loadTaskQueueClockOffset(const std::string& profile); | ||
| 95 | + void resolveCorrelations(); | ||
| 96 | + | ||
| 97 | + friend class AclprofActivityProfilerTestPeer; | ||
| 98 | + friend void recordAclprofTaskQueueEvent( | ||
| 99 | + uint32_t category, | ||
| 100 | + uint64_t taskQueueCorrelation, | ||
| 101 | + int64_t monotonicTimestampNs, | ||
| 102 | + int64_t pid, | ||
| 103 | + int64_t tid, | ||
| 104 | + const std::string& name); | ||
| 105 | + std::set<libkineto::ActivityType> activities_; | ||
| 106 | + std::shared_ptr<detail::AclprofApi> api_; | ||
| 107 | + std::vector<detail::AclprofEvent> events_; | ||
| 108 | + std::vector<std::string> errors_; | ||
| 109 | + std::string root_; | ||
| 110 | + void* config_ = nullptr; | ||
| 111 | + int64_t device_ = -1; | ||
| 112 | + std::mutex correlationMutex_; | ||
| 113 | + std::unordered_map<int64_t, std::vector<std::optional<int32_t>>> activeCorrelations_; | ||
| 114 | + std::vector<TaskQueueMark> taskQueueMarks_; | ||
| 115 | + std::optional<int64_t> taskQueueClockOffsetNs_; | ||
| 116 | + std::vector<std::optional<int32_t>> linkedCorrelations_; | ||
| 117 | + bool initialized_ = false; | ||
| 118 | + bool started_ = false; | ||
| 119 | + bool captureCorrelations_ = false; | ||
| 120 | + bool correlationsResolved_ = false; | ||
| 121 | +}; | ||
| 122 | + | ||
| 123 | +} // namespace profiler | ||
| 124 | +} // namespace torch_npu | ||
| @@ -0,0 +1,42 @@ | |||
| 1 | +#pragma once | ||
| 2 | + | ||
| 3 | +#include <cstdint> | ||
| 4 | +#include <functional> | ||
| 5 | +#include <string> | ||
| 6 | +#include <vector> | ||
| 7 | + | ||
| 8 | +namespace torch_npu::profiler::detail { | ||
| 9 | + | ||
| 10 | +struct AclprofEvent { | ||
| 11 | + std::string name; | ||
| 12 | + std::string taskType; | ||
| 13 | + int64_t startNs = 0; | ||
| 14 | + int64_t endNs = 0; | ||
| 15 | + int64_t device = 0; | ||
| 16 | + int64_t stream = 0; | ||
| 17 | + int64_t correlation = 0; | ||
| 18 | + uint64_t hostLaunchId = 0; | ||
| 19 | + int64_t flowStartNs = 0; | ||
| 20 | + int64_t flowStartPid = -1; | ||
| 21 | + int64_t flowStartTid = -1; | ||
| 22 | +}; | ||
| 23 | + | ||
| 24 | +// physicalDevice is the runtime-resolved physical device for this single-device session. | ||
| 25 | +std::vector<AclprofEvent> parseAclprofTimeline( | ||
| 26 | + const std::string& path, | ||
| 27 | + int64_t physicalDevice, | ||
| 28 | + std::vector<std::string>& errors); | ||
| 29 | + | ||
| 30 | +struct AclprofApi { | ||
| 31 | + std::function<int32_t(int32_t*)> getDevice; | ||
| 32 | + std::function<int32_t(int32_t, int32_t*)> getPhysicalDevice; | ||
| 33 | + std::function<int32_t(const std::string&)> init; | ||
| 34 | + std::function<void*(uint32_t*)> createConfig; | ||
| 35 | + std::function<int32_t()> start; | ||
| 36 | + std::function<int32_t()> registerDeviceCallback; | ||
| 37 | + std::function<int32_t()> stop; | ||
| 38 | + std::function<int32_t()> destroyConfig; | ||
| 39 | + std::function<int32_t()> finalize; | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +} // namespace torch_npu::profiler::detail | ||
| @@ -19,7 +19,6 @@ | |||
| 19 | #include "torch_npu/csrc/framework/interface/MsptiInterface.h" | 19 | #include "torch_npu/csrc/framework/interface/MsptiInterface.h" |
| 20 | #include "torch_npu/csrc/core/npu/npu_log.h" | 20 | #include "torch_npu/csrc/core/npu/npu_log.h" |
| 21 | #include "torch_npu/csrc/toolkit/profiler/common/utils.h" | 21 | #include "torch_npu/csrc/toolkit/profiler/common/utils.h" |
| 22 | -#include <torch/csrc/profiler/standalone/privateuse1_profiler.h> | ||
| 23 | 22 | ||
| 24 | namespace torch_npu { | 23 | namespace torch_npu { |
| 25 | namespace profiler { | 24 | namespace profiler { |
| @@ -47,12 +46,6 @@ bool g_sessionActive = false; | |||
| 47 | 46 | ||
| 48 | int64_t g_corrCounter = 1LL << 30; // 1,073,741,824 (< 2^32 - 1) | 47 | int64_t g_corrCounter = 1LL << 30; // 1,073,741,824 (< 2^32 - 1) |
| 49 | 48 | ||
| 50 | -bool privateUse1Requested(const std::set<libkineto::ActivityType>& types) { | ||
| 51 | - using AT = libkineto::ActivityType; | ||
| 52 | - return types.count(AT::CONCURRENT_KERNEL) != 0 || types.count(AT::GPU_MEMCPY) != 0 || | ||
| 53 | - types.count(AT::GPU_MEMSET) != 0 || types.count(AT::GPU_USER_ANNOTATION) != 0; | ||
| 54 | -} | ||
| 55 | - | ||
| 56 | std::vector<msptiActivityKind> computeEnabledKinds(const std::set<libkineto::ActivityType>& acts) { | 49 | std::vector<msptiActivityKind> computeEnabledKinds(const std::set<libkineto::ActivityType>& acts) { |
| 57 | using AT = libkineto::ActivityType; | 50 | using AT = libkineto::ActivityType; |
| 58 | std::vector<msptiActivityKind> ks; | 51 | std::vector<msptiActivityKind> ks; |
| @@ -426,38 +419,5 @@ std::unique_ptr<libkineto::CpuTraceBuffer> MsptiActivityProfiler::getTraceBuffer | |||
| 426 | return nullptr; | 419 | return nullptr; |
| 427 | } | 420 | } |
| 428 | 421 | ||
| 429 | -std::unique_ptr<libkineto::IActivityProfilerSession> MsptiActivityProfilerPoc::configure( | ||
| 430 | - const std::set<libkineto::ActivityType>& types, | ||
| 431 | - const libkineto::Config&) { | ||
| 432 | - if (!privateUse1Requested(types)) { | ||
| 433 | - return nullptr; | ||
| 434 | - } | ||
| 435 | - return std::make_unique<MsptiActivityProfiler>(types); | ||
| 436 | -} | ||
| 437 | - | ||
| 438 | -std::unique_ptr<libkineto::IActivityProfilerSession> MsptiActivityProfilerPoc::configure( | ||
| 439 | - int64_t, | ||
| 440 | - int64_t, | ||
| 441 | - const std::set<libkineto::ActivityType>& types, | ||
| 442 | - const libkineto::Config& cfg) { | ||
| 443 | - return configure(types, cfg); | ||
| 444 | -} | ||
| 445 | - | ||
| 446 | -// ------------------------------ Registration ------------------------------- | ||
| 447 | -// Prefer the upstream macro (stores the factory in PrivateUse1ProfilerRegistry); | ||
| 448 | -#ifdef REGISTER_PRIVATEUSE1_PROFILER | ||
| 449 | -REGISTER_PRIVATEUSE1_PROFILER(MsptiActivityProfilerPoc); | ||
| 450 | -#else | ||
| 451 | -namespace { | ||
| 452 | -struct MsptiAutoRegister { | ||
| 453 | - MsptiAutoRegister() { | ||
| 454 | - libkineto::api().registerProfilerFactory( | ||
| 455 | - []() -> std::unique_ptr<libkineto::IActivityProfiler> { return std::make_unique<MsptiActivityProfilerPoc>(); }); | ||
| 456 | - } | ||
| 457 | -}; | ||
| 458 | -static MsptiAutoRegister g_mspti_auto_register; | ||
| 459 | -} // namespace | ||
| 460 | -#endif | ||
| 461 | - | ||
| 462 | } // namespace profiler | 422 | } // namespace profiler |
| 463 | } // namespace torch_npu | 423 | } // namespace torch_npu |
| @@ -1,17 +1,12 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | -// mspti NPU activity-profiler session + libkineto bridge. | 2 | +// MSPTI-specific NPU activity-profiler backend. |
| 3 | -// | ||
| 4 | -// MsptiActivityProfilerPoc (libkineto::IActivityProfiler) registers for | ||
| 5 | -// ProfilerActivity.PrivateUse1; configure() returns a MsptiActivityProfiler, | ||
| 6 | -// which is the session libkineto drives. The session enables mspti kinds from | ||
| 7 | -// the requested activity-type set and collects NPU kernel and host API records. | ||
| 8 | 3 | ||
| 9 | #include <memory> | 4 | #include <memory> |
| 10 | #include <set> | 5 | #include <set> |
| 11 | #include <string> | 6 | #include <string> |
| 12 | #include <vector> | 7 | #include <vector> |
| 13 | 8 | ||
| 14 | -#include "IActivityProfiler.h" | 9 | +#include "torch_npu/csrc/profiler/npu_activity_profiler.h" |
| 15 | 10 | ||
| 16 | namespace torch_npu { | 11 | namespace torch_npu { |
| 17 | namespace profiler { | 12 | namespace profiler { |
| @@ -31,10 +26,13 @@ struct MsptiEvent { | |||
| 31 | int64_t streamId = 0; | 26 | int64_t streamId = 0; |
| 32 | }; | 27 | }; |
| 33 | 28 | ||
| 34 | -class MsptiActivityProfiler : public libkineto::IActivityProfilerSession { | 29 | +class MsptiActivityProfiler : public NPUActivityProfiler { |
| 35 | public: | 30 | public: |
| 36 | explicit MsptiActivityProfiler(std::set<libkineto::ActivityType> activities) : activities_(std::move(activities)) {} | 31 | explicit MsptiActivityProfiler(std::set<libkineto::ActivityType> activities) : activities_(std::move(activities)) {} |
| 37 | 32 | ||
| 33 | + const char* name() const override { | ||
| 34 | + return "mspti"; | ||
| 35 | + } | ||
| 38 | void start() override; | 36 | void start() override; |
| 39 | void stop() override; | 37 | void stop() override; |
| 40 | std::vector<std::string> errors() override; | 38 | std::vector<std::string> errors() override; |
| @@ -56,27 +54,5 @@ class MsptiActivityProfiler : public libkineto::IActivityProfilerSession { | |||
| 56 | std::vector<std::string> errors_; | 54 | std::vector<std::string> errors_; |
| 57 | }; | 55 | }; |
| 58 | 56 | ||
| 59 | -class MsptiActivityProfilerPoc : public libkineto::IActivityProfiler { | ||
| 60 | - public: | ||
| 61 | - const std::string& name() const override { | ||
| 62 | - return name_; | ||
| 63 | - } | ||
| 64 | - const std::set<libkineto::ActivityType>& availableActivities() const override { | ||
| 65 | - return avail_; | ||
| 66 | - } | ||
| 67 | - std::unique_ptr<libkineto::IActivityProfilerSession> configure( | ||
| 68 | - const std::set<libkineto::ActivityType>& activity_types, | ||
| 69 | - const libkineto::Config& config) override; | ||
| 70 | - std::unique_ptr<libkineto::IActivityProfilerSession> configure( | ||
| 71 | - int64_t ts_ms, | ||
| 72 | - int64_t duration_ms, | ||
| 73 | - const std::set<libkineto::ActivityType>& activity_types, | ||
| 74 | - const libkineto::Config& config) override; | ||
| 75 | - | ||
| 76 | - private: | ||
| 77 | - std::string name_{"mspti"}; | ||
| 78 | - std::set<libkineto::ActivityType> avail_{libkineto::ActivityType::CONCURRENT_KERNEL}; | ||
| 79 | -}; | ||
| 80 | - | ||
| 81 | } // namespace profiler | 57 | } // namespace profiler |
| 82 | } // namespace torch_npu | 58 | } // namespace torch_npu |
| @@ -0,0 +1,169 @@ | |||
| 1 | +// Copyright (c) 2026 Huawei Technologies Co., Ltd | ||
| 2 | +// All rights reserved. | ||
| 3 | +// | ||
| 4 | +// Licensed under the BSD 3-Clause License (the "License"); | ||
| 5 | +// you may not use this file except in compliance with the License. | ||
| 6 | +// You may obtain a copy of the License at | ||
| 7 | +// | ||
| 8 | +// https://opensource.org/licenses/BSD-3-Clause | ||
| 9 | +// | ||
| 10 | +// Unless required by applicable law or agreed to in writing, software | ||
| 11 | +// distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | +// See the License for the specific language governing permissions and | ||
| 14 | +// limitations under the License. | ||
| 15 | + | ||
| 16 | +#include "torch_npu/csrc/profiler/npu_activity_profiler.h" | ||
| 17 | + | ||
| 18 | +#include <set> | ||
| 19 | +#include <utility> | ||
| 20 | + | ||
| 21 | +#include <nlohmann/json.hpp> | ||
| 22 | +#include <c10/util/Exception.h> | ||
| 23 | + | ||
| 24 | +#include "libkineto.h" | ||
| 25 | +#include "torch_npu/csrc/profiler/aclprof_activity_profiler.h" | ||
| 26 | +#include "torch_npu/csrc/profiler/mspti_activity_profiler.h" | ||
| 27 | +#include <torch/csrc/profiler/standalone/privateuse1_profiler.h> | ||
| 28 | + | ||
| 29 | +namespace torch_npu { | ||
| 30 | +namespace profiler { | ||
| 31 | +namespace { | ||
| 32 | + | ||
| 33 | +bool privateUse1Requested(const std::set<libkineto::ActivityType>& types) { | ||
| 34 | + using AT = libkineto::ActivityType; | ||
| 35 | + return types.count(AT::CONCURRENT_KERNEL) != 0 || types.count(AT::GPU_MEMCPY) != 0 || | ||
| 36 | + types.count(AT::GPU_MEMSET) != 0 || types.count(AT::GPU_USER_ANNOTATION) != 0; | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +NPUProfilerConfig parseExperimentalConfig(const std::string& customConfig) { | ||
| 40 | + NPUProfilerConfig result; | ||
| 41 | + const auto config = nlohmann::json::parse(customConfig, nullptr, false); | ||
| 42 | + if (!config.is_object()) { | ||
| 43 | + return result; | ||
| 44 | + } | ||
| 45 | + const auto backend = config.find("backend"); | ||
| 46 | + if (backend != config.end() && backend->is_string() && backend->get<std::string>() == "aclprof") { | ||
| 47 | + result.backend = "aclprof"; | ||
| 48 | + } | ||
| 49 | + const auto level = config.find("profiler_level"); | ||
| 50 | + if (level != config.end()) { | ||
| 51 | + TORCH_CHECK( | ||
| 52 | + level->is_string() && | ||
| 53 | + (*level == "Level0" || *level == "Level1" || *level == "Level2" || *level == "Level_none"), | ||
| 54 | + "Invalid NPU profiler_level"); | ||
| 55 | + result.profilerLevel = level->get<std::string>(); | ||
| 56 | + } | ||
| 57 | + const auto exports = config.find("export_type"); | ||
| 58 | + if (exports != config.end()) { | ||
| 59 | + TORCH_CHECK(exports->is_array() && !exports->empty(), "Invalid NPU export_type: expected a nonempty array"); | ||
| 60 | + std::set<std::string> values; | ||
| 61 | + for (const auto& value : *exports) { | ||
| 62 | + TORCH_CHECK(value.is_string() && (value == "db" || value == "text"), "Invalid NPU export_type"); | ||
| 63 | + values.insert(value.get<std::string>()); | ||
| 64 | + } | ||
| 65 | + result.exportTypes.assign(values.begin(), values.end()); | ||
| 66 | + } | ||
| 67 | + return result; | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +} // namespace | ||
| 71 | + | ||
| 72 | +std::unique_ptr<NPUActivityProfiler> NPUActivityProfilerFactory::create( | ||
| 73 | + const std::set<libkineto::ActivityType>& activities, | ||
| 74 | + const libkineto::Config& config) { | ||
| 75 | + if (!privateUse1Requested(activities)) { | ||
| 76 | + return nullptr; | ||
| 77 | + } | ||
| 78 | + auto options = parseExperimentalConfig(config.getCustomConfig()); | ||
| 79 | + std::unique_ptr<NPUActivityProfiler> profiler; | ||
| 80 | + if (options.backend == "aclprof") { | ||
| 81 | + profiler = std::make_unique<AclprofActivityProfiler>(activities); | ||
| 82 | + } else { | ||
| 83 | + profiler = std::make_unique<MsptiActivityProfiler>(activities); | ||
| 84 | + } | ||
| 85 | + profiler->config_ = std::move(options); | ||
| 86 | + return profiler; | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +void PrivateUse1ProfilerManager::start() { | ||
| 90 | + profiler_->start(); | ||
| 91 | + status_ = profiler_->status(); | ||
| 92 | +} | ||
| 93 | + | ||
| 94 | +void PrivateUse1ProfilerManager::stop() { | ||
| 95 | + profiler_->stop(); | ||
| 96 | + status_ = profiler_->status(); | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +std::vector<std::string> PrivateUse1ProfilerManager::errors() { | ||
| 100 | + return profiler_->errors(); | ||
| 101 | +} | ||
| 102 | + | ||
| 103 | +void PrivateUse1ProfilerManager::processTrace(libkineto::ActivityLogger& logger) { | ||
| 104 | + profiler_->processTrace(logger); | ||
| 105 | +} | ||
| 106 | + | ||
| 107 | +void PrivateUse1ProfilerManager::processTrace( | ||
| 108 | + libkineto::ActivityLogger& logger, | ||
| 109 | + libkineto::getLinkedActivityCallback getLinkedActivity, | ||
| 110 | + int64_t startTime, | ||
| 111 | + int64_t endTime) { | ||
| 112 | + profiler_->processTrace(logger, std::move(getLinkedActivity), startTime, endTime); | ||
| 113 | +} | ||
| 114 | + | ||
| 115 | +std::unique_ptr<libkineto::DeviceInfo> PrivateUse1ProfilerManager::getDeviceInfo() { | ||
| 116 | + return profiler_->getDeviceInfo(); | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +std::vector<libkineto::ResourceInfo> PrivateUse1ProfilerManager::getResourceInfos() { | ||
| 120 | + return profiler_->getResourceInfos(); | ||
| 121 | +} | ||
| 122 | + | ||
| 123 | +std::unique_ptr<libkineto::CpuTraceBuffer> PrivateUse1ProfilerManager::getTraceBuffer() { | ||
| 124 | + return profiler_->getTraceBuffer(); | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +void PrivateUse1ProfilerManager::pushCorrelationId(uint64_t id) { | ||
| 128 | + profiler_->pushCorrelationId(id); | ||
| 129 | +} | ||
| 130 | + | ||
| 131 | +void PrivateUse1ProfilerManager::popCorrelationId() { | ||
| 132 | + profiler_->popCorrelationId(); | ||
| 133 | +} | ||
| 134 | + | ||
| 135 | +std::unique_ptr<libkineto::IActivityProfilerSession> NPUActivityProfilerPlugin::configure( | ||
| 136 | + const std::set<libkineto::ActivityType>& activityTypes, | ||
| 137 | + const libkineto::Config& config) { | ||
| 138 | + auto profiler = NPUActivityProfilerFactory::create(activityTypes, config); | ||
| 139 | + if (profiler == nullptr) { | ||
| 140 | + return nullptr; | ||
| 141 | + } | ||
| 142 | + return std::make_unique<PrivateUse1ProfilerManager>(std::move(profiler)); | ||
| 143 | +} | ||
| 144 | + | ||
| 145 | +std::unique_ptr<libkineto::IActivityProfilerSession> NPUActivityProfilerPlugin::configure( | ||
| 146 | + int64_t, | ||
| 147 | + int64_t, | ||
| 148 | + const std::set<libkineto::ActivityType>& activityTypes, | ||
| 149 | + const libkineto::Config& config) { | ||
| 150 | + return configure(activityTypes, config); | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +#ifdef REGISTER_PRIVATEUSE1_PROFILER | ||
| 154 | +REGISTER_PRIVATEUSE1_PROFILER(NPUActivityProfilerPlugin); | ||
| 155 | +#else | ||
| 156 | +namespace { | ||
| 157 | +struct NPUProfilerAutoRegister { | ||
| 158 | + NPUProfilerAutoRegister() { | ||
| 159 | + libkineto::api().registerProfilerFactory([]() -> std::unique_ptr<libkineto::IActivityProfiler> { | ||
| 160 | + return std::make_unique<NPUActivityProfilerPlugin>(); | ||
| 161 | + }); | ||
| 162 | + } | ||
| 163 | +}; | ||
| 164 | +static NPUProfilerAutoRegister g_npu_profiler_auto_register; | ||
| 165 | +} // namespace | ||
| 166 | +#endif | ||
| 167 | + | ||
| 168 | +} // namespace profiler | ||
| 169 | +} // namespace torch_npu | ||
| @@ -0,0 +1,126 @@ | |||
| 1 | +// Copyright (c) 2026 Huawei Technologies Co., Ltd | ||
| 2 | +// All rights reserved. | ||
| 3 | +// | ||
| 4 | +// Licensed under the BSD 3-Clause License (the "License"); | ||
| 5 | +// you may not use this file except in compliance with the License. | ||
| 6 | +// You may obtain a copy of the License at | ||
| 7 | +// | ||
| 8 | +// https://opensource.org/licenses/BSD-3-Clause | ||
| 9 | +// | ||
| 10 | +// Unless required by applicable law or agreed to in writing, software | ||
| 11 | +// distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | +// See the License for the specific language governing permissions and | ||
| 14 | +// limitations under the License. | ||
| 15 | + | ||
| 16 | +#pragma once | ||
| 17 | + | ||
| 18 | +#include <memory> | ||
| 19 | +#include <set> | ||
| 20 | +#include <string> | ||
| 21 | +#include <utility> | ||
| 22 | +#include <vector> | ||
| 23 | + | ||
| 24 | +#include "IActivityProfiler.h" | ||
| 25 | +#include "torch_npu/csrc/core/npu/NPUMacros.h" | ||
| 26 | + | ||
| 27 | +namespace torch_npu { | ||
| 28 | +namespace profiler { | ||
| 29 | + | ||
| 30 | +struct NPUProfilerConfig { | ||
| 31 | + std::string backend = "mspti"; | ||
| 32 | + // Empty fields mean unspecified; neither field affects backend selection. | ||
| 33 | + std::string profilerLevel; | ||
| 34 | + std::vector<std::string> exportTypes; | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +class NPUActivityProfiler { | ||
| 38 | + public: | ||
| 39 | + virtual ~NPUActivityProfiler() = default; | ||
| 40 | + | ||
| 41 | + virtual const char* name() const = 0; | ||
| 42 | + virtual void start() = 0; | ||
| 43 | + virtual void stop() = 0; | ||
| 44 | + virtual std::vector<std::string> errors() = 0; | ||
| 45 | + virtual void processTrace(libkineto::ActivityLogger& logger) = 0; | ||
| 46 | + virtual void processTrace( | ||
| 47 | + libkineto::ActivityLogger& logger, | ||
| 48 | + libkineto::getLinkedActivityCallback getLinkedActivity, | ||
| 49 | + int64_t startTime, | ||
| 50 | + int64_t endTime) = 0; | ||
| 51 | + virtual std::unique_ptr<libkineto::DeviceInfo> getDeviceInfo() = 0; | ||
| 52 | + virtual std::vector<libkineto::ResourceInfo> getResourceInfos() = 0; | ||
| 53 | + virtual std::unique_ptr<libkineto::CpuTraceBuffer> getTraceBuffer() = 0; | ||
| 54 | + virtual void pushCorrelationId(uint64_t) {} | ||
| 55 | + virtual void popCorrelationId() {} | ||
| 56 | + | ||
| 57 | + libkineto::TraceStatus status() const { | ||
| 58 | + return status_; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + const NPUProfilerConfig& experimentalConfig() const { | ||
| 62 | + return config_; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + protected: | ||
| 66 | + libkineto::TraceStatus status_ = libkineto::TraceStatus::READY; | ||
| 67 | + | ||
| 68 | + private: | ||
| 69 | + friend class NPUActivityProfilerFactory; | ||
| 70 | + NPUProfilerConfig config_; | ||
| 71 | +}; | ||
| 72 | + | ||
| 73 | +class TORCH_NPU_API NPUActivityProfilerFactory { | ||
| 74 | + public: | ||
| 75 | + static std::unique_ptr<NPUActivityProfiler> create( | ||
| 76 | + const std::set<libkineto::ActivityType>& activities, | ||
| 77 | + const libkineto::Config& config); | ||
| 78 | +}; | ||
| 79 | + | ||
| 80 | +class TORCH_NPU_API PrivateUse1ProfilerManager : public libkineto::IActivityProfilerSession { | ||
| 81 | + public: | ||
| 82 | + explicit PrivateUse1ProfilerManager(std::unique_ptr<NPUActivityProfiler> profiler) : profiler_(std::move(profiler)) {} | ||
| 83 | + | ||
| 84 | + void start() override; | ||
| 85 | + void stop() override; | ||
| 86 | + std::vector<std::string> errors() override; | ||
| 87 | + void processTrace(libkineto::ActivityLogger& logger) override; | ||
| 88 | + void processTrace( | ||
| 89 | + libkineto::ActivityLogger& logger, | ||
| 90 | + libkineto::getLinkedActivityCallback getLinkedActivity, | ||
| 91 | + int64_t startTime, | ||
| 92 | + int64_t endTime) override; | ||
| 93 | + std::unique_ptr<libkineto::DeviceInfo> getDeviceInfo() override; | ||
| 94 | + std::vector<libkineto::ResourceInfo> getResourceInfos() override; | ||
| 95 | + std::unique_ptr<libkineto::CpuTraceBuffer> getTraceBuffer() override; | ||
| 96 | + void pushCorrelationId(uint64_t id) override; | ||
| 97 | + void popCorrelationId() override; | ||
| 98 | + | ||
| 99 | + private: | ||
| 100 | + std::unique_ptr<NPUActivityProfiler> profiler_; | ||
| 101 | +}; | ||
| 102 | + | ||
| 103 | +class TORCH_NPU_API NPUActivityProfilerPlugin : public libkineto::IActivityProfiler { | ||
| 104 | + public: | ||
| 105 | + const std::string& name() const override { | ||
| 106 | + return name_; | ||
| 107 | + } | ||
| 108 | + const std::set<libkineto::ActivityType>& availableActivities() const override { | ||
| 109 | + return avail_; | ||
| 110 | + } | ||
| 111 | + std::unique_ptr<libkineto::IActivityProfilerSession> configure( | ||
| 112 | + const std::set<libkineto::ActivityType>& activityTypes, | ||
| 113 | + const libkineto::Config& config) override; | ||
| 114 | + std::unique_ptr<libkineto::IActivityProfilerSession> configure( | ||
| 115 | + int64_t tsMs, | ||
| 116 | + int64_t durationMs, | ||
| 117 | + const std::set<libkineto::ActivityType>& activityTypes, | ||
| 118 | + const libkineto::Config& config) override; | ||
| 119 | + | ||
| 120 | + private: | ||
| 121 | + std::string name_{"mspti"}; | ||
| 122 | + std::set<libkineto::ActivityType> avail_{libkineto::ActivityType::CONCURRENT_KERNEL}; | ||
| 123 | +}; | ||
| 124 | + | ||
| 125 | +} // namespace profiler | ||
| 126 | +} // namespace torch_npu | ||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "torch_npu/csrc/core/npu/npu_log.h" | 8 | #include "torch_npu/csrc/core/npu/npu_log.h" |
| 9 | #include "torch_npu/csrc/core/npu/NPUException.h" | 9 | #include "torch_npu/csrc/core/npu/NPUException.h" |
| 10 | #include "torch_npu/csrc/core/npu/interface/AclInterface.h" | 10 | #include "torch_npu/csrc/core/npu/interface/AclInterface.h" |
| 11 | +#include "torch_npu/csrc/profiler/aclprof_activity_profiler.h" | ||
| 11 | #include "torch_npu/csrc/profiler/npu_profiler.h" | 12 | #include "torch_npu/csrc/profiler/npu_profiler.h" |
| 12 | 13 | ||
| 13 | #include "torch_npu/csrc/toolkit/profiler/common/utils.h" | 14 | #include "torch_npu/csrc/toolkit/profiler/common/utils.h" |
| @@ -386,6 +387,16 @@ void finalizeNpuProfiler() { | |||
| 386 | } | 387 | } |
| 387 | 388 | ||
| 388 | void reportMarkDataToNpuProfiler(uint32_t category, const std::string& msg, uint64_t correlation_id) { | 389 | void reportMarkDataToNpuProfiler(uint32_t category, const std::string& msg, uint64_t correlation_id) { |
| 390 | + recordAclprofTaskQueueEvent( | ||
| 391 | + category, | ||
| 392 | + correlation_id, | ||
| 393 | + static_cast<int64_t>(Utils::GetClockMonotonicRawNs()), | ||
| 394 | + static_cast<int64_t>(Utils::GetPid()), | ||
| 395 | + static_cast<int64_t>(Utils::GetTid()), | ||
| 396 | + msg); | ||
| 397 | + if (!profDataReportEnable().load(std::memory_order_relaxed)) { | ||
| 398 | + return; | ||
| 399 | + } | ||
| 389 | ProfilerMgr::GetInstance()->UploadWithLock(std::make_unique<torch_npu::toolkit::profiler::OpMarkData>( | 400 | ProfilerMgr::GetInstance()->UploadWithLock(std::make_unique<torch_npu::toolkit::profiler::OpMarkData>( |
| 390 | static_cast<int64_t>(Utils::GetClockTime()), category, correlation_id, Utils::GetTid(), Utils::GetPid(), msg)); | 401 | static_cast<int64_t>(Utils::GetClockTime()), category, correlation_id, Utils::GetTid(), Utils::GetPid(), msg)); |
| 391 | } | 402 | } |
| @@ -9,8 +9,10 @@ from .scheduler import Schedule as schedule | |||
| 9 | from .scheduler import ProfilerAction | 9 | from .scheduler import ProfilerAction |
| 10 | from .experimental_config import _ExperimentalConfig, supported_profiler_level, supported_ai_core_metrics, \ | 10 | from .experimental_config import _ExperimentalConfig, supported_profiler_level, supported_ai_core_metrics, \ |
| 11 | supported_export_type, ProfilerLevel, AiCMetrics, ExportType, HostSystem | 11 | supported_export_type, ProfilerLevel, AiCMetrics, ExportType, HostSystem |
| 12 | +from ._kineto_config import _NPUExperimentalConfig | ||
| 12 | from ._non_intrusive_profile import _NonIntrusiveProfile | 13 | from ._non_intrusive_profile import _NonIntrusiveProfile |
| 13 | 14 | ||
| 14 | __all__ = ["profile", "ProfilerActivity", "supported_activities", "tensorboard_trace_handler", "schedule", | 15 | __all__ = ["profile", "ProfilerActivity", "supported_activities", "tensorboard_trace_handler", "schedule", |
| 15 | - "ProfilerAction", "_ExperimentalConfig", "supported_profiler_level", "supported_ai_core_metrics", | 16 | + "ProfilerAction", "_ExperimentalConfig", "supported_profiler_level", |
| 17 | + "supported_ai_core_metrics", | ||
| 16 | "supported_export_type", "ProfilerLevel", "AiCMetrics", "ExportType", "HostSystem"] | 18 | "supported_export_type", "ProfilerLevel", "AiCMetrics", "ExportType", "HostSystem"] |
| @@ -0,0 +1,56 @@ | |||
| 1 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd | ||
| 2 | +# All rights reserved. | ||
| 3 | +# | ||
| 4 | +# Licensed under the BSD 3-Clause License (the "License"); | ||
| 5 | +# you may not use this file except in compliance with the License. | ||
| 6 | +# You may obtain a copy of the License at | ||
| 7 | +# | ||
| 8 | +# https://opensource.org/licenses/BSD-3-Clause | ||
| 9 | +# | ||
| 10 | +# Unless required by applicable law or agreed to in writing, software | ||
| 11 | +# distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | +# See the License for the specific language governing permissions and | ||
| 14 | +# limitations under the License. | ||
| 15 | + | ||
| 16 | +import json | ||
| 17 | + | ||
| 18 | +from torch._C._profiler import _ExperimentalConfig as ExperimentalConfig | ||
| 19 | + | ||
| 20 | +from .experimental_config import supported_export_type, supported_profiler_level | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +class _NPUExperimentalConfig(ExperimentalConfig): | ||
| 24 | + """Ascend-specific options for ``torch.profiler.profile``. | ||
| 25 | + | ||
| 26 | + Only ``backend="aclprof"`` selects the ACLprof stub. ``profiler_level`` | ||
| 27 | + and ``export_type`` are retained for future implementations; they do not | ||
| 28 | + enable collection or export. ``None`` leaves these options unspecified. | ||
| 29 | + Exports accept an ExportType string or a nonempty list of those strings. | ||
| 30 | + Invalid levels/exports raise ValueError; invalid backends fall back to MSPTI. | ||
| 31 | + """ | ||
| 32 | + | ||
| 33 | + def __init__(self, *, backend: str = "mspti", profiler_level=None, export_type=None, **kwargs): | ||
| 34 | + config = {"backend": backend} | ||
| 35 | + if profiler_level is not None: | ||
| 36 | + if not isinstance(profiler_level, str) or profiler_level not in supported_profiler_level(): | ||
| 37 | + raise ValueError("profiler_level must be a supported ProfilerLevel value") | ||
| 38 | + config["profiler_level"] = profiler_level | ||
| 39 | + if export_type is not None: | ||
| 40 | + exports = [export_type] if isinstance(export_type, str) else export_type | ||
| 41 | + if not isinstance(exports, list) or not exports or any( | ||
| 42 | + not isinstance(value, str) or value not in supported_export_type() for value in exports | ||
| 43 | + ): | ||
| 44 | + raise ValueError("export_type must be an ExportType value or a nonempty list of them") | ||
| 45 | + config["export_type"] = sorted(set(exports)) | ||
| 46 | + super().__init__( | ||
| 47 | + custom_profiler_config=json.dumps(config, separators=(",", ":")), | ||
| 48 | + **kwargs, | ||
| 49 | + ) | ||
| 50 | + | ||
| 51 | + def __str__(self): | ||
| 52 | + # Older PyTorch builds expose this field only through their pickle state. | ||
| 53 | + custom_config = getattr(self, "custom_profiler_config", None) | ||
| 54 | + if custom_config is not None: | ||
| 55 | + return custom_config | ||
| 56 | + return self.__getstate__()[11] | ||