ascend profling

This commit is contained in:
gukecai 2020-08-28 15:45:28 +08:00
parent 34cdab581d
commit 264a556654
9 changed files with 573 additions and 0 deletions

View File

@ -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)

View File

@ -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 ()

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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_