blob: a66b5125d471dfceb58df10c96516df59b7f1710 [file] [log] [blame]
/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
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 TENSORFLOW_CORE_PROFILER_UTILS_GROUP_EVENTS_H_
#define TENSORFLOW_CORE_PROFILER_UTILS_GROUP_EVENTS_H_
#include <memory>
#include "absl/container/flat_hash_map.h"
#include "tensorflow/core/profiler/protobuf/xplane.pb.h"
#include "tensorflow/core/profiler/utils/xplane_visitor.h"
namespace tensorflow {
namespace profiler {
// Information required to connect events across threads. The first two fields
// specify the event types of parent and child events. In addition to matching
// the event types, both events should have stats of the stat types specified
// in stat_types and their values should be the same.
struct InterThreadConnectInfo {
int64 parent_event_type;
int64 child_event_type;
std::vector<int64> stat_types;
};
// A wrapper for XEvent with parent and children pointers. Through these
// pointers, a tree of EventNode is formed.
class EventNode {
public:
// REQUIRED: visitor and event should not be nullptr.
explicit EventNode(const XPlaneVisitor* visitor, XEvent* event)
: visitor_(visitor), event_(event) {
DCHECK(visitor);
DCHECK(event);
}
EventNode* GetParent() const { return parent_; }
const std::vector<EventNode*>& GetChildren() const { return children_; }
void AddChild(EventNode* child) {
children_.push_back(child);
child->parent_ = this;
}
absl::optional<int64> GetGroupId() const { return group_id_; }
std::string GetGroupName() const;
// Sets group_id for this node and its descendants.
void PropagateGroupId(int64 group_id);
const XPlaneVisitor& GetPlaneVisitor() const { return *visitor_; }
const XEvent& GetEvent() const { return *event_; }
const XStat* GetContextStat(int64 stat_type) const;
void AddStepName(absl::string_view step_name);
bool IsNestedIn(EventNode* parent);
private:
const XPlaneVisitor* visitor_;
XEvent* event_;
EventNode* parent_ = nullptr;
std::vector<EventNode*> children_;
absl::optional<int64> group_id_;
};
using EventNodeMap =
absl::flat_hash_map<int64 /*event_type*/,
std::vector<std::unique_ptr<EventNode>>>;
using VirtualEventContainer = std::vector<std::unique_ptr<XEvent>>;
using EventGroupNameMap = absl::flat_hash_map<int64 /*group_id*/, std::string>;
// Creates a forest of EventNode by stitching events in space using the nesting
// relationship within the same thread and connect_info_list across threads, and
// groups them by the root events.
class EventForest {
public:
EventForest(const std::vector<InterThreadConnectInfo>& connect_info_list,
const std::vector<int64>& root_event_types,
const std::function<XPlaneVisitor(const XPlane*)> visitor_factory,
XSpace* space);
const EventNodeMap& GetEventNodeMap() const { return event_node_map_; }
const EventGroupNameMap& GetEventGroupNameMap() const {
return event_group_name_map_;
}
private:
// Creates an EventNode for each event in event_node_map and connect events
// according to the nesting relationship within the thread.
void ConnectIntraThread(const XPlaneVisitor& visitor, XPlane* plane);
// Connects events across threads according to connect_info_list.
void ConnectInterThread(
const std::vector<InterThreadConnectInfo>& connect_info_list);
// Creates event groups and populates event_group_name_map_. For each event of
// each event type in root_event_types in order, if it was not grouped yet, a
// new group is created with all the events reachable from the root event.
void CreateEventGroup(
const std::vector<int64 /*EventType*/>& root_event_types);
// Create virtual events of HostEventType::kHostTrainingLoopIteration and
// event nodes for them. A virtual event is created for each iteration of the
// host training loop and connected to the
// HostEventType::kExecutorStateProcess event nodes of the iteration.
void CreateVirtualEventsForHostTrainingLoop();
// Create virutal events of HostEventType::kAsyncExecutorTraceContext and
// event nodes for them. A virtual event is created for every FunctionRun and
// the following eager ops (e.g., for Keras callback).
void CreateVirtualEventsForAsyncExecutor();
EventNodeMap event_node_map_;
std::vector<XPlaneVisitor> visitors_;
VirtualEventContainer virtual_event_container_;
EventGroupNameMap event_group_name_map_;
};
// Calls GroupEvents with connect_info_list and root_event_types specific to
// TensorFlow.
void GroupTfEvents(XSpace* space, EventGroupNameMap* event_group_name_map);
} // namespace profiler
} // namespace tensorflow
#endif // TENSORFLOW_CORE_PROFILER_UTILS_GROUP_EVENTS_H_