[Bf-blender-cvs] [2025a21499f] profiler-editor: add layout class
Jacques Lucke
noreply at git.blender.org
Thu Apr 29 11:30:47 CEST 2021
Commit: 2025a21499f36cff735fef93f59545e5a4fb1ab1
Author: Jacques Lucke
Date: Tue Apr 27 15:12:49 2021 +0200
Branches: profiler-editor
https://developer.blender.org/rB2025a21499f36cff735fef93f59545e5a4fb1ab1
add layout class
===================================================================
M source/blender/blenlib/intern/profile.cc
M source/blender/editors/space_profiler/CMakeLists.txt
A source/blender/editors/space_profiler/profiler_layout.cc
A source/blender/editors/space_profiler/profiler_layout.hh
===================================================================
diff --git a/source/blender/blenlib/intern/profile.cc b/source/blender/blenlib/intern/profile.cc
index 844a829be18..9b265a61093 100644
--- a/source/blender/blenlib/intern/profile.cc
+++ b/source/blender/blenlib/intern/profile.cc
@@ -100,15 +100,15 @@ void ProfileListener::flush_to_all()
{
/* Todo: How to handle short lived threads? */
std::scoped_lock lock{listeners_mutex, registered_threadlocals_mutex};
+ RecordedProfile recorded_profile;
for (ThreadLocalProfileData *data : registered_threadlocals) {
- RecordedProfile recorded_profile;
data->queue_begins.consume(
[&](Span<ProfileTaskBegin> data) { recorded_profile.task_begins.extend(data); });
data->queue_ends.consume(
[&](Span<ProfileTaskEnd> data) { recorded_profile.task_ends.extend(data); });
- for (ProfileListener *listener : listeners) {
- listener->handle(recorded_profile);
- }
+ }
+ for (ProfileListener *listener : listeners) {
+ listener->handle(recorded_profile);
}
}
diff --git a/source/blender/editors/space_profiler/CMakeLists.txt b/source/blender/editors/space_profiler/CMakeLists.txt
index b4407a7d1e8..9ac83285321 100644
--- a/source/blender/editors/space_profiler/CMakeLists.txt
+++ b/source/blender/editors/space_profiler/CMakeLists.txt
@@ -27,7 +27,10 @@ set(INC
)
set(SRC
+ profiler_layout.cc
space_profiler.cc
+
+ profiler_layout.hh
)
set(LIB
diff --git a/source/blender/editors/space_profiler/profiler_layout.cc b/source/blender/editors/space_profiler/profiler_layout.cc
new file mode 100644
index 00000000000..dcc1ba9d3a7
--- /dev/null
+++ b/source/blender/editors/space_profiler/profiler_layout.cc
@@ -0,0 +1,215 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "profiler_layout.hh"
+
+#include "BLI_set.hh"
+
+namespace blender::ed::profiler {
+
+using profile::ProfileTaskBegin;
+using profile::ProfileTaskEnd;
+
+bool ProfileNode::time_overlap(const ProfileNode &a, const ProfileNode &b)
+{
+ const bool begin_of_a_is_in_b = (a.begin_time_ > b.begin_time_ && a.begin_time_ < b.end_time_);
+ const bool begin_of_b_is_in_a = (b.begin_time_ > a.begin_time_ && b.begin_time_ < a.end_time_);
+ return begin_of_a_is_in_b || begin_of_b_is_in_a;
+}
+
+void ProfileNode::pack_added_children()
+{
+ /* Sort new nodes by begin time. */
+ std::sort(children_to_pack_.begin(),
+ children_to_pack_.end(),
+ [](ProfileNode *a, ProfileNode *b) { return a->begin_time() < b->begin_time(); });
+
+ /* Assume already packed children are sorted by begin time. */
+ int tot_newly_inserted = 0;
+ tot_newly_inserted += this->try_pack_into_vector(children_on_same_thread_, true);
+
+ int iteration = 0;
+ while (tot_newly_inserted < children_to_pack_.size()) {
+ if (iteration == packed_children_on_other_threads_.size()) {
+ packed_children_on_other_threads_.append({});
+ }
+ Vector<ProfileNode *> &children_vec = packed_children_on_other_threads_[iteration];
+ iteration++;
+ tot_newly_inserted += this->try_pack_into_vector(children_vec, false);
+ }
+
+ children_to_pack_.clear();
+}
+
+int ProfileNode::try_pack_into_vector(Vector<ProfileNode *> &nodes_vec,
+ bool ignore_other_thread_ids)
+{
+ int tot_newly_inserted = 0;
+ MutableSpan<ProfileNode *> remaining_existing = nodes_vec;
+ MutableSpan<ProfileNode *> remaining_new = children_to_pack_;
+ Vector<ProfileNode *> new_vec;
+ while (!remaining_new.is_empty()) {
+ ProfileNode *new_child = remaining_new[0];
+ if (new_child == nullptr) {
+ /* Child has been inserted already. */
+ remaining_new = remaining_new.drop_front(1);
+ continue;
+ }
+ if (ignore_other_thread_ids) {
+ if (new_child->thread_id_ != thread_id_) {
+ /* Child is ignored because it is in another thread. */
+ remaining_new = remaining_new.drop_front(1);
+ continue;
+ }
+ }
+ while (true) {
+ if (!new_vec.is_empty()) {
+ ProfileNode *existing_child = new_vec.last();
+ if (ProfileNode::time_overlap(*existing_child, *new_child)) {
+ /* Node collides with previously added node. */
+ remaining_new = remaining_new.drop_front(1);
+ break;
+ }
+ }
+ if (remaining_existing.is_empty()) {
+ /* There are no remaining existing nodes the new child can collide with. */
+ new_vec.append(new_child);
+ tot_newly_inserted++;
+ remaining_new[0] = nullptr;
+ remaining_new = remaining_new.drop_front(1);
+ break;
+ }
+ ProfileNode *existing_child = remaining_existing[0];
+ if (existing_child->end_time_ <= new_child->begin_time_) {
+ /* Existing child is completely before the new one. */
+ new_vec.append(existing_child);
+ remaining_existing = remaining_existing.drop_front(1);
+ continue;
+ }
+ if (existing_child->begin_time_ < new_child->end_time_) {
+ /* Existing child collides with the new child. */
+ new_vec.append(existing_child);
+ remaining_existing = remaining_existing.drop_front(1);
+ remaining_new = remaining_new.drop_front(1);
+ break;
+ }
+ if (new_child->end_time_ <= existing_child->begin_time_) {
+ /* New child can be added safely. */
+ new_vec.append(new_child);
+ tot_newly_inserted++;
+ remaining_new[0] = nullptr;
+ remaining_new = remaining_new.drop_front(1);
+ break;
+ }
+ }
+ }
+ new_vec.extend(remaining_existing);
+ nodes_vec = std::move(new_vec);
+ return tot_newly_inserted;
+}
+
+void ProfileLayout::add(const RecordedProfile &recorded_profile)
+{
+ /* Create new nodes for segments and add them to the id map. */
+ for (const ProfileTaskBegin &task_begin : recorded_profile.task_begins) {
+ ProfileNode &node = *allocator_.construct<ProfileNode>().release();
+ node.name_ = task_begin.name;
+ node.begin_time_ = task_begin.time;
+ node.end_time_ = TimePoint{}; /* The end time is not known yet. */
+ node.id_ = task_begin.id;
+ node.parent_id_ = task_begin.parent_id;
+ node.thread_id_ = task_begin.thread_id;
+ nodes_by_id_.add_new(task_begin.id, &node);
+ }
+ for (const ProfileTaskEnd &task_end : recorded_profile.task_ends) {
+ ProfileNode *node = nodes_by_id_.lookup_default(task_end.begin_id, nullptr);
+ if (node != nullptr) {
+ BLI_assert(node->end_time_ == TimePoint{});
+ node->end_time_ = task_end.time;
+ }
+ }
+
+ Set<ProfileNode *> nodes_with_new_children;
+
+ /* Create parent/child relation ships for new nodes. */
+ for (const ProfileTaskBegin &task_begin : recorded_profile.task_begins) {
+ ProfileNode *node = nodes_by_id_.lookup(task_begin.id);
+ ProfileNode *parent_node = nodes_by_id_.lookup_default(task_begin.parent_id, nullptr);
+ node->parent_ = parent_node;
+ if (parent_node == nullptr) {
+ if (root_thread_ids_.is_empty()) {
+ begin_time_ = node->begin_time_;
+ end_time_ = node->end_time_;
+ }
+ else {
+ begin_time_ = std::min(begin_time_, node->begin_time_);
+ end_time_ = std::max(end_time_, node->end_time_);
+ }
+ root_thread_ids_.append_non_duplicates(node->thread_id_);
+ root_nodes_by_thread_id_.lookup_or_add_default(node->thread_id_).append(node);
+ }
+ else {
+ parent_node->children_to_pack_.append(node);
+ nodes_with_new_children.add(parent_node);
+ }
+ }
+
+ /* Check if a previous root node is not a root anymore. */
+ for (Vector<ProfileNode *> &nodes : root_nodes_by_thread_id_.values()) {
+ Vector<ProfileNode *> nodes_that_are_not_root_anymore;
+ for (ProfileNode *node : nodes) {
+ ProfileNode *new_parent = nodes_by_id_.lookup_default(node->parent_id_, nullptr);
+ if (new_parent != nullptr) {
+ node->parent_ = new_parent;
+ new_parent->children_to_pack_.append(node);
+ nodes_with_new_children.add(new_parent);
+ nodes_that_are_not_root_anymore.append_non_duplicates(node);
+ }
+ }
+ for (ProfileNode *node : nodes_that_are_not_root_anymore) {
+ nodes.remove_first_occurrence_and_reorder(node);
+ }
+ }
+
+ /* Pack newly added children. */
+ for (ProfileNode *node : nodes_with_new_children) {
+ node->pack_added_children();
+ }
+}
+
+void ProfileNode::destruct_recursively()
+{
+ for (ProfileNode *node : children_on_same_thread_) {
+ node->destruct_recursively();
+ }
+ for (Span<ProfileNode *> nodes : packed_children_on_other_threads_) {
+ for (ProfileNode *node : nodes) {
+ node->destruct_recursively();
+ }
+ }
+ this->~ProfileNode();
+}
+
+ProfileLayout::~ProfileLayout()
+{
+ for (Span<ProfileNode *> nodes : root_nodes_by_thread_id_.values()) {
+ for (ProfileNode *node : nodes) {
+ node->destruct_recursively();
+ }
+ }
+}
+
+} // namespace blender::ed::profiler
diff --git a/source/blender/editors/space_profiler/profiler_layout.hh b/source/blender/editors/space_profiler/profiler_layout.hh
new file mode 100644
index 00000000000..4c780744f4b
--- /dev/null
+++ b/source/blender/editors/space_profiler/profiler_layout.hh
@@ -0,0 +1,141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; w
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list