1#include "taichi/system/timeline.h"
2
3namespace taichi {
4
5std::string TimelineEvent::to_json() {
6 std::string json{"{"};
7 json += fmt::format("\"cat\":\"taichi\",");
8 json += fmt::format("\"pid\":0,");
9 json += fmt::format("\"tid\":\"{}\",", tid);
10 json += fmt::format("\"ph\":\"{}\",", begin ? "B" : "E");
11 json += fmt::format("\"name\":\"{}\",", name);
12 json += fmt::format("\"ts\":\"{}\"", uint64(time * 1000000));
13 json += "}";
14 return json;
15}
16
17Timeline::Timeline() : tid_("unnamed") {
18 Timelines::get_instance().insert_timeline(this);
19}
20
21Timeline &Timeline::get_this_thread_instance() {
22 thread_local Timeline instance;
23 return instance;
24}
25
26Timeline::~Timeline() {
27 Timelines::get_instance().insert_events(fetch_events());
28 Timelines::get_instance().remove_timeline(this);
29}
30
31void Timeline::clear() {
32 std::lock_guard<std::mutex> _(mut_);
33 events_.clear();
34}
35void Timeline::insert_event(const TimelineEvent &e) {
36 if (!Timelines::get_instance().get_enabled())
37 return;
38 std::lock_guard<std::mutex> _(mut_);
39 events_.push_back(e);
40}
41
42std::vector<TimelineEvent> Timeline::fetch_events() {
43 std::lock_guard<std::mutex> _(mut_);
44 std::vector<TimelineEvent> fetched;
45 std::swap(fetched, events_);
46 return fetched;
47}
48
49Timeline::Guard::Guard(const std::string &name) : name_(name) {
50 auto &timeline = Timeline::get_this_thread_instance();
51 timeline.insert_event({name, true, Time::get_time(), timeline.tid_});
52}
53
54Timeline::Guard::~Guard() {
55 auto &timeline = Timeline::get_this_thread_instance();
56 timeline.insert_event({name_, false, Time::get_time(), timeline.tid_});
57}
58
59void Timelines::insert_events(const std::vector<TimelineEvent> &events) {
60 std::lock_guard<std::mutex> _(mut_);
61 insert_events_without_locking(events);
62}
63
64void Timelines::insert_events_without_locking(
65 const std::vector<TimelineEvent> &events) {
66 events_.insert(events_.end(), events.begin(), events.end());
67}
68
69Timelines &taichi::Timelines::get_instance() {
70 static auto instance = new Timelines();
71 return *instance;
72}
73
74void Timelines::clear() {
75 std::lock_guard<std::mutex> _(mut_);
76 events_.clear();
77 for (auto timeline : timelines_) {
78 timeline->clear();
79 }
80}
81
82void Timelines::save(const std::string &filename) {
83 std::lock_guard<std::mutex> _(mut_);
84 std::sort(timelines_.begin(), timelines_.end(), [](Timeline *a, Timeline *b) {
85 return a->get_name() < b->get_name();
86 });
87 for (auto timeline : timelines_) {
88 insert_events_without_locking(timeline->fetch_events());
89 }
90 if (!ends_with(filename, ".json")) {
91 TI_WARN("Timeline filename {} should end with '.json'.", filename);
92 }
93 std::ofstream fout(filename);
94 fout << "[";
95 bool first = true;
96 for (auto &e : events_) {
97 if (first) {
98 first = false;
99 } else {
100 fout << ",";
101 }
102 fout << e.to_json() << std::endl;
103 }
104 fout << "]";
105}
106
107void Timelines::insert_timeline(Timeline *timeline) {
108 std::lock_guard<std::mutex> _(mut_);
109 timelines_.push_back(timeline);
110}
111
112void Timelines::remove_timeline(Timeline *timeline) {
113 std::lock_guard<std::mutex> _(mut_);
114 trash(std::remove(timelines_.begin(), timelines_.end(), timeline));
115}
116
117bool Timelines::get_enabled() {
118 return enabled_;
119}
120
121void Timelines::set_enabled(bool enabled) {
122 enabled_ = enabled;
123}
124
125} // namespace taichi
126