Merge pull request !5596 from gukecai/profilingtags/v1.0.0
| @@ -48,6 +48,7 @@ endif() | |||
| include(${CMAKE_SOURCE_DIR}/cmake/mind_expression.cmake) | |||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}) | |||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/securec/include) | |||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/flatbuffers/include) | |||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/flatbuffers/include/flatbuffers) | |||
| @@ -2,4 +2,10 @@ if (ENABLE_GPU) | |||
| file(GLOB_RECURSE PROFILER_SRC_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "device/gpu/*.cc") | |||
| set_property(SOURCE ${PROFILER_SRC_LIST} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_PROFILER) | |||
| add_library(_mindspore_profiler_obj OBJECT ${PROFILER_SRC_LIST}) | |||
| endif () | |||
| if (ENABLE_D) | |||
| file(GLOB_RECURSE PROFILER_SRC_LIST RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "device/ascend/*.cc") | |||
| set_property(SOURCE ${PROFILER_SRC_LIST} PROPERTY COMPILE_DEFINITIONS SUBMODULE_ID=mindspore::SubModuleId::SM_PROFILER) | |||
| add_library(_mindspore_profiler_obj OBJECT ${PROFILER_SRC_LIST}) | |||
| endif () | |||
| @@ -0,0 +1,83 @@ | |||
| /** | |||
| * Copyright 2019-2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * 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 "profiler/device/ascend/ascend_profiling.h" | |||
| #include <cstdarg> | |||
| #include <iomanip> | |||
| #include <utility> | |||
| #include "utils/log_adapter.h" | |||
| #include "./securec.h" | |||
| namespace mindspore { | |||
| namespace profiler { | |||
| namespace ascend { | |||
| const int kMaxEvents = 10000; | |||
| const int kEventDescMax = 256; | |||
| const int kMaxEventTypes = 8; | |||
| const int kIndent = 8; | |||
| AscendProfiler::AscendProfiler() : counter_(0) { Reset(); } | |||
| void AscendProfiler::RecordEvent(EventType event_type, const char *fmt, ...) { | |||
| va_list args; | |||
| va_start(args, fmt); | |||
| char buf[kEventDescMax]; | |||
| if (vsnprintf_s(buf, kEventDescMax, kEventDescMax - 1, fmt, args) == -1) { | |||
| MS_LOG(ERROR) << "format failed:" << fmt; | |||
| va_end(args); | |||
| return; | |||
| } | |||
| va_end(args); | |||
| std::string event = buf; | |||
| auto index = counter_++; | |||
| auto &evt = events_[index]; | |||
| evt.timestamp = std::chrono::system_clock::now(); | |||
| evt.desc = std::move(event); | |||
| evt.event_type = event_type; | |||
| } | |||
| void AscendProfiler::Dump(std::ostream &output_stream) { | |||
| MS_LOG(INFO) << "start dump async profiling info"; | |||
| if (events_.empty()) { | |||
| return; | |||
| } | |||
| auto first_evt = events_[0]; | |||
| auto start = first_evt.timestamp; | |||
| std::vector<decltype(start)> prev_timestamps; | |||
| prev_timestamps.resize(kMaxEventTypes, start); | |||
| for (int i = 0; i < counter_; ++i) { | |||
| auto &evt = events_[i]; | |||
| auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(evt.timestamp - start).count(); | |||
| auto &prev_ts = prev_timestamps[evt.event_type]; | |||
| auto cost = std::chrono::duration_cast<std::chrono::microseconds>(evt.timestamp - prev_ts).count(); | |||
| prev_ts = evt.timestamp; | |||
| output_stream << std::setw(kIndent) << elapsed << "\t\t" << cost << "\t\t" << evt.desc << std::endl; | |||
| } | |||
| events_.clear(); | |||
| MS_LOG(INFO) << "end"; | |||
| } | |||
| void AscendProfiler::Reset() { | |||
| counter_ = 0; | |||
| events_.clear(); | |||
| events_.resize(kMaxEvents); | |||
| } | |||
| } // namespace ascend | |||
| } // namespace profiler | |||
| } // namespace mindspore | |||
| @@ -0,0 +1,60 @@ | |||
| /** | |||
| * Copyright 2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * 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. | |||
| */ | |||
| #ifndef MINDSPORE_ASCEND_PROFILING_H_ | |||
| #define MINDSPORE_ASCEND_PROFILING_H_ | |||
| #include <atomic> | |||
| #include <chrono> | |||
| #include <mutex> | |||
| #include <ostream> | |||
| #include <string> | |||
| #include <vector> | |||
| using std::string; | |||
| namespace mindspore { | |||
| namespace profiler { | |||
| namespace ascend { | |||
| enum EventType { kGeneral = 0, kCompiler, kExecution, kCallback }; | |||
| struct Event { | |||
| std::chrono::system_clock::time_point timestamp; | |||
| EventType event_type; | |||
| std::string desc; | |||
| }; | |||
| class AscendProfiler { | |||
| public: | |||
| AscendProfiler(); | |||
| ~AscendProfiler() = default; | |||
| static AscendProfiler &GetInstance() { | |||
| static AscendProfiler instance; | |||
| return instance; | |||
| } | |||
| void RecordEvent(EventType event_type, const char *fmt, ...); | |||
| void Reset(); | |||
| void Dump(std::ostream &os); | |||
| private: | |||
| std::vector<Event> events_; | |||
| std::atomic_int counter_; | |||
| }; | |||
| } // namespace ascend | |||
| } // namespace profiler | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_ASCEND_PROFILING_H_ | |||
| @@ -0,0 +1,147 @@ | |||
| /** | |||
| * Copyright 2019-2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * 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. | |||
| */ | |||
| #ifndef MINDSPORE_BLOCKING_QUEUE_H_ | |||
| #define MINDSPORE_BLOCKING_QUEUE_H_ | |||
| #include <stdint.h> | |||
| #include <condition_variable> | |||
| #include <list> | |||
| #include <mutex> | |||
| #include <utility> | |||
| static const int kDefaultMaxQueueSize = 2048; | |||
| namespace mindspore { | |||
| namespace profiler { | |||
| namespace ascend { | |||
| template <typename T> | |||
| class BlockingQueue { | |||
| public: | |||
| explicit BlockingQueue(uint32_t max_size = kDefaultMaxQueueSize) : max_size_(max_size), is_stoped_(false) {} | |||
| ~BlockingQueue() {} | |||
| bool Pop(T *item) { | |||
| std::unique_lock<std::mutex> lock(mutex_); | |||
| while (queue_.empty() && !is_stoped_) { | |||
| empty_cond_.wait(lock); | |||
| } | |||
| if (is_stoped_) { | |||
| return false; | |||
| } | |||
| *item = std::move(queue_.front()); | |||
| queue_.pop_front(); | |||
| full_cond_.notify_one(); | |||
| return true; | |||
| } | |||
| bool Push(const T &item, bool is_wait = true) { | |||
| std::unique_lock<std::mutex> lock(mutex_); | |||
| while (queue_.size() >= max_size_ && !is_stoped_) { | |||
| if (!is_wait) { | |||
| return false; | |||
| } | |||
| full_cond_.wait(lock); | |||
| } | |||
| if (is_stoped_) { | |||
| return false; | |||
| } | |||
| queue_.push_back(item); | |||
| empty_cond_.notify_one(); | |||
| return true; | |||
| } | |||
| bool Push(T &&item, bool is_wait = true) { | |||
| std::unique_lock<std::mutex> lock(mutex_); | |||
| while (queue_.size() >= max_size_ && !is_stoped_) { | |||
| if (!is_wait) { | |||
| return false; | |||
| } | |||
| full_cond_.wait(lock); | |||
| } | |||
| if (is_stoped_) { | |||
| return false; | |||
| } | |||
| queue_.emplace_back(std::move(item)); | |||
| empty_cond_.notify_one(); | |||
| return true; | |||
| } | |||
| void Stop() { | |||
| { | |||
| std::unique_lock<std::mutex> lock(mutex_); | |||
| is_stoped_ = true; | |||
| } | |||
| full_cond_.notify_all(); | |||
| empty_cond_.notify_all(); | |||
| } | |||
| void Restart() { | |||
| std::unique_lock<std::mutex> lock(mutex_); | |||
| is_stoped_ = false; | |||
| } | |||
| // if the queue is stoped ,need call this function to release the unprocessed items | |||
| std::list<T> GetRemainItems() { | |||
| std::unique_lock<std::mutex> lock(mutex_); | |||
| if (!is_stoped_) { | |||
| return std::list<T>(); | |||
| } | |||
| return queue_; | |||
| } | |||
| bool IsFull() { | |||
| std::unique_lock<std::mutex> lock(mutex_); | |||
| return queue_.size() >= max_size_; | |||
| } | |||
| void Clear() { | |||
| std::unique_lock<std::mutex> lock(mutex_); | |||
| queue_.clear(); | |||
| } | |||
| private: | |||
| std::list<T> queue_; | |||
| std::mutex mutex_; | |||
| std::condition_variable empty_cond_; | |||
| std::condition_variable full_cond_; | |||
| uint32_t max_size_; | |||
| bool is_stoped_; | |||
| }; | |||
| } // namespace ascend | |||
| } // namespace profiler | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_BLOCKING_QUEUE_H_ | |||
| @@ -0,0 +1,23 @@ | |||
| /** | |||
| * Copyright 2019-2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * 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 "profiler/device/ascend/profiling_context.h" | |||
| namespace mindspore { | |||
| namespace profiler { | |||
| namespace ascend {} | |||
| } // namespace profiler | |||
| } // namespace mindspore | |||
| @@ -0,0 +1,60 @@ | |||
| /** | |||
| * Copyright 2019-2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * 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. | |||
| */ | |||
| #ifndef MINDSPORE_PROFILING_CONTEXT_H_ | |||
| #define MINDSPORE_PROFILING_CONTEXT_H_ | |||
| #include <sys/syscall.h> | |||
| #include <unistd.h> | |||
| #include <atomic> | |||
| #include <cstdint> | |||
| #include <unordered_map> | |||
| #include "profiler/device/ascend/ascend_profiling.h" | |||
| namespace mindspore { | |||
| namespace profiler { | |||
| namespace ascend { | |||
| inline pid_t GetTid() { | |||
| thread_local static pid_t tid = syscall(__NR_gettid); | |||
| return tid; | |||
| } | |||
| #define RECORD_PROFILING_EVENT(profiler, evt_type, fmt, category, node_name, ...) \ | |||
| do { \ | |||
| if (profiler != nullptr) { \ | |||
| if (node_name != nullptr) { \ | |||
| profiler->RecordEvent(evt_type, "tid:%lu [%s] [%s] " fmt, GetTid(), node_name, category, ##__VA_ARGS__); \ | |||
| } else { \ | |||
| profiler->RecordEvent(evt_type, "tid:%lu [%s] " fmt, GetTid(), category, ##__VA_ARGS__); \ | |||
| } \ | |||
| } \ | |||
| } while (0) | |||
| #define RECORD_MODEL_EXECUTION_EVENT(profiler, fmt, ...) \ | |||
| RECORD_PROFILING_EVENT((profiler), kGeneral, fmt, "ModelExecutor", nullptr, ##__VA_ARGS__) | |||
| #define RECORD_COMPILE_EVENT(profiler, name, fmt, ...) \ | |||
| RECORD_PROFILING_EVENT((profiler), kCompiler, fmt, "Compilation", name, ##__VA_ARGS__) | |||
| #define RECORD_EXECUTION_EVENT(profiler, name, fmt, ...) \ | |||
| RECORD_PROFILING_EVENT((profiler), kExecution, fmt, "Execution", name, ##__VA_ARGS__) | |||
| #define RECORD_CALLBACK_EVENT(profiler, name, fmt, ...) \ | |||
| RECORD_PROFILING_EVENT((profiler), kCallback, fmt, "Callback", name, ##__VA_ARGS__) | |||
| } // namespace ascend | |||
| } // namespace profiler | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_PROFILING_CONTEXT_H_ | |||
| @@ -0,0 +1,130 @@ | |||
| /** | |||
| * Copyright 2019-2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * 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 "profiler/device/ascend/rt_callback_manager.h" | |||
| #include "utils/log_adapter.h" | |||
| #include "runtime/event.h" | |||
| namespace mindspore { | |||
| namespace profiler { | |||
| namespace ascend { | |||
| CallbackManager::CallbackManager(rtStream_t stream) : stream_(stream) {} | |||
| Status CallbackManager::Init() { | |||
| MS_LOG(INFO) << "CallbackManager init, Start to async process event"; | |||
| ret_future_ = std::async([&] { return CallbackProcess(); }); | |||
| if (!ret_future_.valid()) { | |||
| MS_LOG(ERROR) << "Failed to init callback manager."; | |||
| return kFail; | |||
| } | |||
| return kSuccess; | |||
| } | |||
| Status CallbackManager::CallbackProcess() { | |||
| std::pair<rtEvent_t, std::pair<rtCallback_t, void *>> entry; | |||
| while (true) { | |||
| if (!callback_queue_.Pop(&entry)) { | |||
| MS_LOG(INFO) << "CallbackManager stopped"; | |||
| return kFail; | |||
| } | |||
| auto event = entry.first; | |||
| if (event == nullptr) { | |||
| return kSuccess; | |||
| } | |||
| auto rt_err = rtEventSynchronize(event); | |||
| if (rt_err != RT_ERROR_NONE) { | |||
| MS_LOG(ERROR) << "rtEventSynchronize failed. ret:" << rt_err; | |||
| auto ret = rtEventDestroy(event); | |||
| if (ret != RT_ERROR_NONE) { | |||
| MS_LOG(ERROR) << "rtEventDestroy failed"; | |||
| } | |||
| return kFail; | |||
| } | |||
| auto ret = rtEventDestroy(event); | |||
| if (ret != RT_ERROR_NONE) { | |||
| MS_LOG(ERROR) << "rtEventDestroy failed"; | |||
| } | |||
| auto cb_func = entry.second.first; | |||
| auto cb_args = entry.second.second; | |||
| cb_func(cb_args); | |||
| } | |||
| } | |||
| Status CallbackManager::Destroy() { | |||
| MS_LOG(INFO) << "To destroy callback manager."; | |||
| if (!ret_future_.valid()) { | |||
| MS_LOG(INFO) << "CallbackManager not initialized."; | |||
| return kSuccess; | |||
| } | |||
| std::pair<rtEvent_t, std::pair<rtCallback_t, void *>> eof_entry; | |||
| eof_entry.first = nullptr; | |||
| callback_queue_.Push(eof_entry); | |||
| auto ret = ret_future_.get(); | |||
| MS_LOG(INFO) << "Callback manager ended. ret:" << ret; | |||
| return ret; | |||
| } | |||
| Status CallbackManager::RegisterCallback(rtCallback_t callback, void *user_data) { | |||
| MS_LOG(INFO) << "To register callback"; | |||
| rtEvent_t event = nullptr; | |||
| auto ret = rtEventCreate(&event); | |||
| if (ret != RT_ERROR_NONE) { | |||
| MS_LOG(ERROR) << "Create event failed"; | |||
| return kFail; | |||
| } | |||
| ret = rtEventRecord(event, stream_); | |||
| if (ret != RT_ERROR_NONE) { | |||
| MS_LOG(ERROR) << "Record event failed"; | |||
| return kFail; | |||
| } | |||
| auto cb = std::pair<rtCallback_t, void *>(callback, user_data); | |||
| auto entry = std::pair<rtEvent_t, std::pair<rtCallback_t, void *>>(event, std::move(cb)); | |||
| if (!callback_queue_.Push(entry)) { | |||
| return kFail; | |||
| } | |||
| MS_LOG(INFO) << "Registering callback successfully"; | |||
| return kSuccess; | |||
| } | |||
| void CallbackManager::RtCallbackFunc(void *data) { | |||
| MS_LOG(INFO) << "To invoke callback function"; | |||
| auto callback_func = reinterpret_cast<std::function<void()> *>(data); | |||
| (*callback_func)(); | |||
| delete callback_func; | |||
| } | |||
| Status CallbackManager::RegisterCallback(const std::function<void()> &callback) { | |||
| auto func = std::unique_ptr<std::function<void()>>(new (std::nothrow) std::function<void()>(callback)); | |||
| if (func == nullptr) { | |||
| MS_LOG(ERROR) << "callback is nullptr"; | |||
| return kInvalidParam; | |||
| } | |||
| MS_LOG(INFO) << "Callback registered"; | |||
| return RegisterCallback(RtCallbackFunc, func.release()); | |||
| } | |||
| } // namespace ascend | |||
| } // namespace profiler | |||
| } // namespace mindspore | |||
| @@ -0,0 +1,63 @@ | |||
| /** | |||
| * Copyright 2019-2020 Huawei Technologies Co., Ltd | |||
| * | |||
| * 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. | |||
| */ | |||
| #ifndef MINDSPORE_RT_CALLBACK_MANAGER_H_ | |||
| #define MINDSPORE_RT_CALLBACK_MANAGER_H_ | |||
| #include <condition_variable> | |||
| #include <functional> | |||
| #include <future> | |||
| #include <memory> | |||
| #include <utility> | |||
| #include "profiler/device/ascend/blocking_queue.h" | |||
| #include "runtime/base.h" | |||
| namespace mindspore { | |||
| namespace profiler { | |||
| namespace ascend { | |||
| using rtCallback_t = std::function<void(void *)>; | |||
| enum Status { kSuccess = 0, kFail, kInvalidParam }; | |||
| class CallbackManager { | |||
| public: | |||
| static CallbackManager &GetInstance(rtStream_t stream) { | |||
| static CallbackManager instance(stream); | |||
| return instance; | |||
| } | |||
| explicit CallbackManager(rtStream_t stream); | |||
| ~CallbackManager() = default; | |||
| Status Init(); | |||
| Status Destroy(); | |||
| Status RegisterCallback(rtCallback_t callback, void *user_data); | |||
| Status RegisterCallback(const std::function<void()> &callback); | |||
| private: | |||
| Status CallbackProcess(); | |||
| static void RtCallbackFunc(void *data); | |||
| BlockingQueue<std::pair<rtEvent_t, std::pair<rtCallback_t, void *>>> callback_queue_; | |||
| rtStream_t stream_; | |||
| std::future<Status> ret_future_; | |||
| }; | |||
| } // namespace ascend | |||
| } // namespace profiler | |||
| } // namespace mindspore | |||
| #endif // MINDSPORE_RT_CALLBACK_MANAGER_H_ | |||