Skip to content

Commit

Permalink
Sync profiler (open-mmlab#1446)
Browse files Browse the repository at this point in the history
* Sdk profiler (open-mmlab#1274)

* sdk-profiler

* fix lint

* support lift

* sync net module when profile

* use Scope*

* update use task name

* fix

* use std::unique_ptr<Event>

* remove mmdeploy::graph link for c and transform

* fix

* fix

* fix

* [Enhancement] refactor profiler (open-mmlab#1403)

* reduce profile node name

* add profiler for pipeline

* add profiler for cond

* udpate

* fix total time (open-mmlab#1451)
  • Loading branch information
irexyc authored Dec 7, 2022
1 parent 817917f commit c4e95f1
Show file tree
Hide file tree
Showing 19 changed files with 4,217 additions and 5 deletions.
20 changes: 20 additions & 0 deletions csrc/mmdeploy/apis/c/mmdeploy/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "common_internal.h"
#include "executor_internal.h"
#include "mmdeploy/core/mat.h"
#include "mmdeploy/core/profiler.h"

mmdeploy_value_t mmdeploy_value_copy(mmdeploy_value_t value) {
if (!value) {
Expand Down Expand Up @@ -72,6 +73,19 @@ int mmdeploy_device_create(const char* device_name, int device_id, mmdeploy_devi

void mmdeploy_device_destroy(mmdeploy_device_t device) { delete (Device*)device; }

int mmdeploy_profiler_create(const char* path, mmdeploy_profiler_t* profiler) {
*profiler = (mmdeploy_profiler_t) new profiler::Profiler(path);
return MMDEPLOY_SUCCESS;
}

void mmdeploy_profiler_destroy(mmdeploy_profiler_t profiler) {
if (profiler) {
auto p = (profiler::Profiler*)profiler;
p->Release();
delete p;
}
}

int mmdeploy_context_add(mmdeploy_context_t context, mmdeploy_context_type_t type, const char* name,
const void* object) {
auto& ctx = *Cast(context);
Expand All @@ -88,6 +102,12 @@ int mmdeploy_context_add(mmdeploy_context_t context, mmdeploy_context_type_t typ
case MMDEPLOY_TYPE_MODEL:
ctx["model"][name] = *Cast((const mmdeploy_model_t)object);
break;
case MMDEPLOY_TYPE_PROFILER: {
const auto& profiler = *(profiler::Profiler*)object;
profiler::Scope* root(profiler.scope());
ctx["scope"] = root;
break;
}
default:
return MMDEPLOY_E_NOT_SUPPORTED;
}
Expand Down
18 changes: 18 additions & 0 deletions csrc/mmdeploy/apis/c/mmdeploy/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ typedef enum mmdeploy_status_t {

typedef struct mmdeploy_device* mmdeploy_device_t;

typedef struct mmdeploy_profiler* mmdeploy_profiler_t;

typedef struct mmdeploy_mat_t {
uint8_t* data;
int height;
Expand Down Expand Up @@ -88,6 +90,7 @@ typedef enum mmdeploy_context_type_t {
MMDEPLOY_TYPE_MODEL = 2,
MMDEPLOY_TYPE_SCHEDULER = 3,
MMDEPLOY_TYPE_MAT = 4,
MMDEPLOY_TYPE_PROFILER = 5,
} mmdeploy_context_type_t;

#if __cplusplus
Expand Down Expand Up @@ -123,6 +126,21 @@ MMDEPLOY_API int mmdeploy_device_create(const char* device_name, int device_id,
*/
MMDEPLOY_API void mmdeploy_device_destroy(mmdeploy_device_t device);

/**
* Create profiler
* @param path path to save the profile data
* @param profiler handle for profiler, should be added to context and deleted by
* mmdeploy_profiler_destroy
* @return status of create
*/
MMDEPLOY_API int mmdeploy_profiler_create(const char* path, mmdeploy_profiler_t* profiler);

/**
* Destroy profiler handle
* @param profiler handle for profiler, profile data will be written to disk after this call
*/
MMDEPLOY_API void mmdeploy_profiler_destroy(mmdeploy_profiler_t profiler);

/**
* Create context
* @param context
Expand Down
23 changes: 23 additions & 0 deletions csrc/mmdeploy/apis/cxx/mmdeploy/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,24 @@ class Device {
std::shared_ptr<mmdeploy_device> device_;
};

class Profiler {
public:
explicit Profiler(std::string_view path) : path_(path) {
mmdeploy_profiler_t profiler{};
auto ec = mmdeploy_profiler_create(path_.c_str(), &profiler);
if (ec != MMDEPLOY_SUCCESS) {
throw_exception(static_cast<ErrorCode>(ec));
}
profiler_.reset(profiler, [](auto p) { mmdeploy_profiler_destroy(p); });
};

operator mmdeploy_profiler_t() const noexcept { return profiler_.get(); }

private:
std::string path_;
std::shared_ptr<mmdeploy_profiler> profiler_;
};

class Mat {
public:
Mat() : desc_{} {}
Expand Down Expand Up @@ -187,6 +205,10 @@ class Context {
mmdeploy_context_add(*this, MMDEPLOY_TYPE_DEVICE, nullptr, device);
}

void Add(const Profiler& profiler) {
mmdeploy_context_add(*this, MMDEPLOY_TYPE_PROFILER, nullptr, profiler);
}

operator mmdeploy_context_t() const noexcept { return context_.get(); }

private:
Expand All @@ -199,6 +221,7 @@ using cxx::Context;
using cxx::Device;
using cxx::Mat;
using cxx::Model;
using cxx::Profiler;
using cxx::Rect;
using cxx::Scheduler;

Expand Down
3 changes: 2 additions & 1 deletion csrc/mmdeploy/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,16 @@ set(SRCS
utils/device_utils.cpp
utils/formatter.cpp
utils/stacktrace.cpp
profiler.cpp
)

mmdeploy_add_library(${PROJECT_NAME} ${SRCS})


target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/csrc>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/third_party/outcome>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/third_party/concurrentqueue>
# TODO: remove dependency of `json`
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/third_party/json>
)
Expand Down
87 changes: 87 additions & 0 deletions csrc/mmdeploy/core/profiler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) OpenMMLab. All rights reserved.

#include "mmdeploy/core/profiler.h"

#include <iomanip>

namespace mmdeploy {
namespace profiler {

Event* Scope::Add(Event::Type type, Index index, TimePoint time_point) {
return profiler_->AddEvent({this, type, index, time_point});
}

Scope* Scope::CreateScope(std::string_view name) {
auto node = children_.emplace_back(profiler_->CreateScope(name));
node->parent_ = this;
return node;
}

void Scope::Dump(Scope* scope, std::ofstream& ofs) {
ofs << scope->name_ << " " << (void*)scope << " ";
for (auto& child : scope->children_) {
ofs << (void*)child << " ";
}
ofs << "\n";
for (const auto& child : scope->children_) {
Dump(child, ofs);
}
}

ScopedCounter::ScopedCounter(Scope* scope) {
if (scope) {
start_ = scope->Add(Event::kStart, scope->next_.fetch_add(1, std::memory_order_relaxed),
Clock::now());
}
}

ScopedCounter::~ScopedCounter() {
if (start_) {
start_->scope->Add(Event::kEnd, start_->index, Clock::now());
}
}

Profiler::Profiler(std::string_view path) : path_(path) { root_ = CreateScope("."); }

Scope* Profiler::CreateScope(std::string_view name) {
auto& node = nodes_.emplace_back();
node.profiler_ = this;
node.name_ = name;
return &node;
}

Event* Profiler::AddEvent(Event e) {
auto uptr = std::make_unique<Event>(e);
Event* pe = uptr.get();
events_.enqueue(std::move(uptr));
return pe;
}

void Profiler::Release() {
std::ofstream ofs(path_);
root_->Dump(ofs);
ofs << "----\n";

std::unique_ptr<Event> item;
std::vector<std::unique_ptr<Event>> vec;
while (events_.try_dequeue(item)) {
vec.push_back(std::move(item));
}

std::sort(vec.begin(), vec.end(),
[](const std::unique_ptr<Event>& a, const std::unique_ptr<Event>& b) {
return a->time_point < b->time_point;
});

for (int i = 0; i < vec.size(); i++) {
ofs << (void*)vec[i]->scope << " " << vec[i]->type << " " << vec[i]->index << " "
<< std::chrono::duration_cast<std::chrono::microseconds>(vec[i]->time_point -
vec[0]->time_point)
.count()
<< "\n";
}
}

} // namespace profiler

} // namespace mmdeploy
86 changes: 86 additions & 0 deletions csrc/mmdeploy/core/profiler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) OpenMMLab. All rights reserved.

#ifndef MMDEPLOY_CSRC_MMDEPLOY_CORE_PROFILER_H_
#define MMDEPLOY_CSRC_MMDEPLOY_CORE_PROFILER_H_

#include <atomic>
#include <chrono>
#include <deque>
#include <fstream>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>

#include "concurrentqueue.h"
#include "mmdeploy/core/logger.h"
#include "mmdeploy/core/macro.h"
#include "mmdeploy/core/value.h"

namespace mmdeploy {
namespace profiler {

struct Profiler;
struct Scope;

using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock, std::chrono::steady_clock>;
using TimePoint = Clock::time_point;
using Index = uint64_t;

struct Event {
enum Type { kStart, kEnd };
Scope* scope;
Type type;
Index index;
TimePoint time_point;
};

struct MMDEPLOY_API Scope {
Scope() = default;
Scope(const Scope&) = delete;
Scope(Scope&&) noexcept = delete;
Scope& operator=(const Scope&) = delete;
Scope& operator=(Scope&&) noexcept = delete;

Event* Add(Event::Type type, Index index, TimePoint time_point);

Scope* CreateScope(std::string_view name);

void Dump(Scope* scope, std::ofstream& ofs);
void Dump(std::ofstream& ofs) { Dump(this, ofs); }

Profiler* profiler_{};
Scope* parent_{};
std::vector<Scope*> children_;
std::atomic<Index> next_{};
std::string name_;
};

struct MMDEPLOY_API ScopedCounter {
explicit ScopedCounter(Scope* scope);
~ScopedCounter();

Event* start_{};
};

struct MMDEPLOY_API Profiler {
explicit Profiler(std::string_view path);
Scope* CreateScope(std::string_view name);
Event* AddEvent(Event e);
Scope* scope() const noexcept { return root_; }
void Release();

std::string path_;
std::deque<Scope> nodes_;
moodycamel::ConcurrentQueue<std::unique_ptr<Event>> events_;
Scope* root_{};
};

} // namespace profiler

MMDEPLOY_REGISTER_TYPE_ID(profiler::Scope*, 10);

} // namespace mmdeploy

#endif // MMDEPLOY_CSRC_MMDEPLOY_GRAPH_PROFILER_H_
25 changes: 24 additions & 1 deletion csrc/mmdeploy/graph/cond.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,16 @@ Value get_divergent_output(Value::Array& rs, const vector<int>& ps) {
} // namespace

Sender<Value> Cond::Process(Sender<Value> input) {
return LetValue(std::move(input), [this](Value& _input) -> Sender<Value> {
auto index = std::make_shared<profiler::Index>();
if (scope_) {
*index = scope_->next_.fetch_add(1, std::memory_order_relaxed);
input = Then(std::move(input), [this, index](Value v) mutable {
scope_->Add(profiler::Event::kStart, *index, profiler::Clock::now());
return std::move(v);
});
}

Sender<Value> output = LetValue(std::move(input), [this](Value& _input) -> Sender<Value> {
assert(_input.is_array());
auto& as = _input.array();
auto ps = get_predicates(as.front().array());
Expand All @@ -75,6 +84,14 @@ Sender<Value> Cond::Process(Sender<Value> input) {
});
}
});

if (scope_) {
output = Then(std::move(output), [this, index](Value v) {
scope_->Add(profiler::Event::kEnd, *index, profiler::Clock::now());
return std::move(v);
});
}
return output;
}

CondBuilder::CondBuilder(Value config) : Builder(std::move(config)) {}
Expand All @@ -97,6 +114,12 @@ Result<unique_ptr<Node>> CondBuilder::BuildImpl() {
}
if (config_.contains("context")) {
update(body_config["context"].object(), config_["context"].object(), 2);
if (config_["context"].contains("scope")) {
auto scope = config_["context"]["scope"].get<profiler::Scope*>();
auto name = config_.value("name", std::string("Cond"));
cond->scope_ = scope->CreateScope(name);
body_config["context"]["scope"] = cond->scope_;
}
}

if (auto builder = Builder::CreateFromConfig(body_config).value()) {
Expand Down
2 changes: 2 additions & 0 deletions csrc/mmdeploy/graph/cond.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#define MMDEPLOY_CSRC_MMDEPLOY_GRAPH_COND_H_

#include "mmdeploy/core/graph.h"
#include "mmdeploy/core/profiler.h"

namespace mmdeploy::graph {

Expand All @@ -14,6 +15,7 @@ class Cond : public Node {
Sender<Value> Process(Sender<Value> input) override;

private:
profiler::Scope* scope_{nullptr};
std::unique_ptr<Node> node_;
int n_output_{0};
};
Expand Down
6 changes: 6 additions & 0 deletions csrc/mmdeploy/graph/inference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "mmdeploy/archive/json_archive.h"
#include "mmdeploy/core/graph.h"
#include "mmdeploy/core/model.h"
#include "mmdeploy/core/profiler.h"
#include "mmdeploy/graph/common.h"

namespace mmdeploy::graph {
Expand Down Expand Up @@ -33,6 +34,11 @@ Result<unique_ptr<Node>> InferenceBuilder::BuildImpl() {
context["model"] = std::move(model);

auto pipeline_config = from_json<Value>(json);
if (context.contains("scope")) {
auto name = config_.value("name", config_["type"].get<std::string>());
auto scope = context["scope"].get_ref<profiler::Scope*&>()->CreateScope(name);
context["scope"] = scope;
}
pipeline_config["context"] = context;

MMDEPLOY_INFO("{}", pipeline_config);
Expand Down
Loading

0 comments on commit c4e95f1

Please sign in to comment.