From 2e8de70cb78791a9b076abe7bca7b34acbe3837b Mon Sep 17 00:00:00 2001 From: PaddlePaddle-Gardener Date: Thu, 13 Jan 2022 14:21:15 +0800 Subject: [PATCH] mirgate_38779 --- paddle/fluid/platform/CMakeLists.txt | 1 + paddle/fluid/platform/os_info.cc | 206 ++++++++++++++++++ paddle/fluid/platform/os_info.h | 75 +++++++ paddle/fluid/platform/os_info_test.cc | 40 ++++ .../platform/profiler/host_event_recorder.cc | 33 +++ 5 files changed, 355 insertions(+) create mode 100644 paddle/fluid/platform/os_info_test.cc diff --git a/paddle/fluid/platform/CMakeLists.txt b/paddle/fluid/platform/CMakeLists.txt index 8a84429987..517b4a28a6 100644 --- a/paddle/fluid/platform/CMakeLists.txt +++ b/paddle/fluid/platform/CMakeLists.txt @@ -47,6 +47,7 @@ ENDIF() cc_library(cpu_info SRCS cpu_info.cc DEPS ${CPU_INFO_DEPS}) cc_test(cpu_info_test SRCS cpu_info_test.cc DEPS cpu_info) cc_library(os_info SRCS os_info.cc DEPS enforce) +cc_test(os_info_test SRCS os_info_test.cc DEPS os_info) IF(WITH_GPU) nv_library(cuda_graph_with_memory_pool SRCS cuda_graph_with_memory_pool.cc DEPS device_context allocator_facade cuda_graph) diff --git a/paddle/fluid/platform/os_info.cc b/paddle/fluid/platform/os_info.cc index e69de29bb2..0726315316 100644 --- a/paddle/fluid/platform/os_info.cc +++ b/paddle/fluid/platform/os_info.cc @@ -0,0 +1,206 @@ +/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#include "paddle/fluid/platform/os_info.h" +#include +#include +#include +#include +#include +#if defined(__linux__) +#include +#include +#include +#elif defined(_MSC_VER) +#include +#endif +#include "paddle/fluid/platform/macros.h" // import DISABLE_COPY_AND_ASSIGN + +namespace paddle { +namespace platform { +namespace internal { + +static uint64_t main_tid = + std::hash()(std::this_thread::get_id()); + +template +class ThreadDataRegistry { + class ThreadDataHolder; + + public: + // Singleton + static ThreadDataRegistry& GetInstance() { + static ThreadDataRegistry instance; + return instance; + } + + const T& GetCurrentThreadData() { return CurrentThreadData(); } + + void SetCurrentThreadData(const T& val) { + std::lock_guard lock(lock_); + CurrentThreadData() = val; + } + + // Returns current snapshot of all threads. Make sure there is no thread + // create/destory when using it. + template ::value>> + std::unordered_map GetAllThreadDataByValue() { + std::unordered_map data_copy; + std::lock_guard lock(lock_); + data_copy.reserve(tid_map_.size()); + for (auto& kv : tid_map_) { + data_copy.emplace(kv.first, kv.second->GetData()); + } + return std::move(data_copy); + } + + void RegisterData(uint64_t tid, ThreadDataHolder* tls_obj) { + std::lock_guard lock(lock_); + tid_map_[tid] = tls_obj; + } + + void UnregisterData(uint64_t tid) { + if (tid == main_tid) { + return; + } + std::lock_guard lock(lock_); + tid_map_.erase(tid); + } + + private: + class ThreadDataHolder { + public: + ThreadDataHolder() { + tid_ = std::hash()(std::this_thread::get_id()); + ThreadDataRegistry::GetInstance().RegisterData(tid_, this); + } + + ~ThreadDataHolder() { + ThreadDataRegistry::GetInstance().UnregisterData(tid_); + } + + T& GetData() { return data_; } + + private: + uint64_t tid_; + T data_; + }; + + ThreadDataRegistry() = default; + + DISABLE_COPY_AND_ASSIGN(ThreadDataRegistry); + + T& CurrentThreadData() { + static thread_local ThreadDataHolder thread_data; + return thread_data.GetData(); + } + + std::mutex lock_; + std::unordered_map tid_map_; // not owned +}; + +class InternalThreadId { + public: + InternalThreadId(); + + const ThreadId& GetTid() const { return id_; } + + private: + ThreadId id_; +}; + +InternalThreadId::InternalThreadId() { + // C++ std tid + id_.std_tid = std::hash()(std::this_thread::get_id()); +// system tid +#if defined(__linux__) + id_.sys_tid = static_cast(syscall(SYS_gettid)); +#elif defined(_MSC_VER) + id_.sys_tid = static_cast(::GetCurrentThreadId()); +#else // unsupported platforms, use std_tid + id_.sys_tid = id_.std_tid; +#endif + // cupti tid + std::stringstream ss; + ss << std::this_thread::get_id(); + id_.cupti_tid = static_cast(std::stoull(ss.str())); +} + +} // namespace internal + +uint64_t GetCurrentThreadSysId() { + return internal::ThreadDataRegistry::GetInstance() + .GetCurrentThreadData() + .GetTid() + .sys_tid; +} + +uint64_t GetCurrentThreadStdId() { + return internal::ThreadDataRegistry::GetInstance() + .GetCurrentThreadData() + .GetTid() + .std_tid; +} + +ThreadId GetCurrentThreadId() { + return internal::ThreadDataRegistry::GetInstance() + .GetCurrentThreadData() + .GetTid(); +} + +std::unordered_map GetAllThreadIds() { + auto tids = + internal::ThreadDataRegistry::GetInstance() + .GetAllThreadDataByValue(); + std::unordered_map res; + for (const auto& kv : tids) { + res[kv.first] = kv.second.GetTid(); + } + return res; +} + +static constexpr const char* kDefaultThreadName = "unset"; + +std::string GetCurrentThreadName() { + const auto& thread_name = + internal::ThreadDataRegistry::GetInstance() + .GetCurrentThreadData(); + return thread_name.empty() ? kDefaultThreadName : thread_name; +} + +std::unordered_map GetAllThreadNames() { + return internal::ThreadDataRegistry::GetInstance() + .GetAllThreadDataByValue(); +} + +bool SetCurrentThreadName(const std::string& name) { + auto& instance = internal::ThreadDataRegistry::GetInstance(); + const auto& cur_name = instance.GetCurrentThreadData(); + if (!cur_name.empty() || cur_name == kDefaultThreadName) { + return false; + } + instance.SetCurrentThreadData(name); + return true; +} + +uint32_t GetProcessId() { +#if defined(_MSC_VER) + return static_cast(GetCurrentProcessId()); +#else + return static_cast(getpid()); +#endif +} + +} // namespace platform +} // namespace paddle diff --git a/paddle/fluid/platform/os_info.h b/paddle/fluid/platform/os_info.h index e69de29bb2..c84738247a 100644 --- a/paddle/fluid/platform/os_info.h +++ b/paddle/fluid/platform/os_info.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#pragma once + +#include +#include +#ifdef _POSIX_C_SOURCE +#include +#endif +#include "paddle/fluid/platform/port.h" + +namespace paddle { +namespace platform { + +// Get system-wide realtime clock in nanoseconds +inline uint64_t PosixInNsec() { +#ifdef _POSIX_C_SOURCE + struct timespec tp; + clock_gettime(CLOCK_REALTIME, &tp); + return tp.tv_sec * 1000 * 1000 * 1000 + tp.tv_nsec; +#else + struct timeval tv; + gettimeofday(&tv, nullptr); + return 1000 * (static_cast(tv.tv_sec) * 1000000 + tv.tv_usec); +#endif +} + +// All kinds of Ids for OS thread +struct ThreadId { + uint64_t std_tid = 0; // std::hash + uint64_t sys_tid = 0; // OS-specific, Linux: gettid + uint32_t cupti_tid = 0; // thread_id used by Nvidia CUPTI +}; + +// Better performance than GetCurrentThreadId +uint64_t GetCurrentThreadStdId(); + +// Better performance than GetCurrentThreadId +uint64_t GetCurrentThreadSysId(); + +ThreadId GetCurrentThreadId(); + +// Return the map from StdTid to ThreadId +// Returns current snapshot of all threads. Make sure there is no thread +// create/destory when using it. +std::unordered_map GetAllThreadIds(); + +// Returns 'unset' if SetCurrentThreadName is never called. +std::string GetCurrentThreadName(); + +// Return the map from StdTid to ThreadName +// Returns current snapshot of all threads. Make sure there is no thread +// create/destory when using it. +std::unordered_map GetAllThreadNames(); + +// Thread name is immutable, only the first call will succeed. +// Returns false on failure. +bool SetCurrentThreadName(const std::string& name); + +uint32_t GetProcessId(); + +} // namespace platform +} // namespace paddle diff --git a/paddle/fluid/platform/os_info_test.cc b/paddle/fluid/platform/os_info_test.cc new file mode 100644 index 0000000000..b309bb9851 --- /dev/null +++ b/paddle/fluid/platform/os_info_test.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "paddle/fluid/platform/os_info.h" +#include +#include "gtest/gtest.h" + +TEST(ThreadInfo, TestThreadIdUtils) { + using paddle::platform::GetCurrentThreadStdId; + using paddle::platform::GetCurrentThreadId; + using paddle::platform::GetAllThreadIds; + EXPECT_EQ(std::hash()(std::this_thread::get_id()), + GetCurrentThreadId().std_tid); + auto ids = GetAllThreadIds(); + EXPECT_TRUE(ids.find(GetCurrentThreadStdId()) != ids.end()); +} + +TEST(ThreadInfo, TestThreadNameUtils) { + using paddle::platform::GetCurrentThreadStdId; + using paddle::platform::GetCurrentThreadName; + using paddle::platform::SetCurrentThreadName; + using paddle::platform::GetAllThreadNames; + EXPECT_EQ("unset", GetCurrentThreadName()); + EXPECT_TRUE(SetCurrentThreadName("MainThread")); + EXPECT_FALSE(SetCurrentThreadName("MainThread")); + auto names = GetAllThreadNames(); + EXPECT_TRUE(names.find(GetCurrentThreadStdId()) != names.end()); + EXPECT_EQ("MainThread", names[GetCurrentThreadStdId()]); + EXPECT_EQ("MainThread", GetCurrentThreadName()); +} diff --git a/paddle/fluid/platform/profiler/host_event_recorder.cc b/paddle/fluid/platform/profiler/host_event_recorder.cc index e69de29bb2..b8495ca45c 100644 --- a/paddle/fluid/platform/profiler/host_event_recorder.cc +++ b/paddle/fluid/platform/profiler/host_event_recorder.cc @@ -0,0 +1,33 @@ +/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#include "paddle/fluid/platform/profiler/host_event_recorder.h" +#include "paddle/fluid/platform/os_info.h" + +namespace paddle { +namespace platform { + +ThreadEventRecorder::ThreadEventRecorder() { + thread_id_ = GetCurrentThreadSysId(); + HostEventRecorder::GetInstance().RegisterThreadRecorder(thread_id_, this); +} + +HostEventSection HostEventRecorder::GatherEvents() { + HostEventSection host_sec; + host_sec.thr_sections.reserve(thread_recorders_.size()); + for (auto &kv : thread_recorders_) { + host_sec.thr_sections.emplace_back(std::move(kv.second->GatherEvents())); + } + return host_sec; +} + +} // namespace platform +} // namespace paddle -- Gitee