blob: 24ced4494201d7c8bbb3f30f6eb947581ef40c7a [file] [log] [blame]
//
// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include "TimelineModel.hpp"
#include <common/include/LabelsAndEventClasses.hpp>
#include <algorithm>
namespace arm
{
namespace pipe
{
void TimelineModel::AddLabel(const arm::pipe::ITimelineDecoder::Label& label)
{
m_LabelMap.emplace(label.m_Guid, label);
}
std::string* TimelineModel::FindLabel(uint64_t guid)
{
auto iter = m_LabelMap.find(guid);
if (iter != m_LabelMap.end())
{
return &iter->second.m_Name;
}
else
{
return nullptr;
}
}
void TimelineModel::AddEntity(uint64_t guid)
{
m_Entities.emplace(guid, guid);
}
Entity* TimelineModel::FindEntity(uint64_t id)
{
auto iter = m_Entities.find(id);
if (iter != m_Entities.end())
{
return &(iter->second);
}
else
{
return nullptr;
}
}
void TimelineModel::AddRelationship(const arm::pipe::ITimelineDecoder::Relationship& relationship)
{
m_Relationships.emplace(relationship.m_Guid, relationship);
if (relationship.m_RelationshipType == arm::pipe::ITimelineDecoder::RelationshipType::LabelLink)
{
HandleLabelLink(relationship);
}
else if (relationship.m_RelationshipType == ITimelineDecoder::RelationshipType::RetentionLink)
{
// Take care of the special case of a connection between layers in ArmNN
// modelled by a retention link between two layer entities with an attribute GUID
// of connection
if (relationship.m_AttributeGuid == LabelsAndEventClasses::CONNECTION_GUID)
{
HandleConnection(relationship);
}
else if (relationship.m_AttributeGuid == LabelsAndEventClasses::CHILD_GUID)
{
HandleChild(relationship);
}
else if (relationship.m_AttributeGuid == LabelsAndEventClasses::EXECUTION_OF_GUID)
{
HandleExecutionOf(relationship);
}
else
{
// report unknown relationship type
std::stringstream ss;
ss << "Encountered a RetentionLink of unknown type [" << relationship.m_AttributeGuid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
}
}
else if (relationship.m_RelationshipType == arm::pipe::ITimelineDecoder::RelationshipType::ExecutionLink)
{
HandleExecutionLink(relationship);
}
}
void TimelineModel::HandleLabelLink(const arm::pipe::ITimelineDecoder::Relationship& relationship)
{
Entity* entity = FindEntity(relationship.m_HeadGuid);
// we have a label attribute of an entity
std::string* value = nullptr;
std::string* attribute = nullptr;
value = FindLabel(relationship.m_TailGuid);
if (value == nullptr)
{
//report an error
std::stringstream ss;
ss << "could not find label link [" << relationship.m_Guid <<
"] value [" << relationship.m_TailGuid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
}
if (relationship.m_AttributeGuid != 0)
{
attribute = FindLabel(relationship.m_AttributeGuid);
if (attribute == nullptr)
{
//report an error
std::stringstream ss;
ss << "could not find label link [" << relationship.m_Guid <<
"] attribute [" << relationship.m_AttributeGuid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
}
}
else
{
//report an error
std::stringstream ss;
ss << "label link [" << relationship.m_Guid << "] has a zero attribute guid";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
}
if (entity != nullptr && attribute != nullptr && value != nullptr)
{
entity->AddAttribute(*attribute, *value);
// if the attribute is 'type' and the value is 'inference'
// we need to cache the entity guid as an inference
if (LabelsAndEventClasses::TYPE_LABEL.compare(*attribute) == 0 &&
LabelsAndEventClasses::INFERENCE.compare(*value) == 0)
{
m_InferenceGuids.push_back(relationship.m_HeadGuid);
}
}
if (entity == nullptr)
{
//report an error
std::stringstream ss;
ss << "could not find label link [" << relationship.m_Guid <<
"] entity [" << relationship.m_HeadGuid << "] ";
if (value != nullptr)
{
ss << "value [" << *value << "] ";
}
if (attribute != nullptr)
{
ss << "attribute [" << *attribute << "] ";
}
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
}
}
void TimelineModel::HandleConnection(const arm::pipe::ITimelineDecoder::Relationship& relationship)
{
Entity* outputLayer = FindEntity(relationship.m_HeadGuid);
if (outputLayer == nullptr)
{
std::stringstream ss;
ss << "could not find output entity [" << relationship.m_HeadGuid << "]";
ss << " of connection [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
Entity* inputLayer = FindEntity(relationship.m_TailGuid);
if (inputLayer == nullptr)
{
std::stringstream ss;
ss << "could not find input entity [" << relationship.m_TailGuid << "]";
ss << " of connection [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
Connection connection(relationship.m_Guid, outputLayer, inputLayer);
outputLayer->AddConnection(connection);
}
void TimelineModel::HandleChild(const arm::pipe::ITimelineDecoder::Relationship& relationship)
{
Entity* parentEntity = FindEntity(relationship.m_HeadGuid);
if (parentEntity == nullptr)
{
std::stringstream ss;
ss << "could not find parent entity [" << relationship.m_HeadGuid << "]";
ss << " of child relationship [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
Entity* childEntity = FindEntity(relationship.m_TailGuid);
if (childEntity == nullptr)
{
std::stringstream ss;
ss << "could not find child entity [" << relationship.m_TailGuid << "]";
ss << " of child relationship [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
parentEntity->AddChild(childEntity);
}
void TimelineModel::HandleExecutionOf(const arm::pipe::ITimelineDecoder::Relationship& relationship)
{
Entity* parentEntity = FindEntity(relationship.m_HeadGuid);
if (parentEntity == nullptr)
{
std::stringstream ss;
ss << "could not find parent entity [" << relationship.m_HeadGuid << "]";
ss << " of execution relationship [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
Entity* executedEntity = FindEntity(relationship.m_TailGuid);
if (executedEntity == nullptr)
{
std::stringstream ss;
ss << "could not find executed entity [" << relationship.m_TailGuid << "]";
ss << " of execution relationship [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
parentEntity->AddExecution(executedEntity);
}
void TimelineModel::HandleExecutionLink(const arm::pipe::ITimelineDecoder::Relationship& relationship)
{
// entityGuid,
Entity* parentEntity = FindEntity(relationship.m_HeadGuid);
if (parentEntity == nullptr)
{
std::stringstream ss;
ss << "could not find entity [" << relationship.m_HeadGuid << "]";
ss << " of ExecutionLink [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
// eventGuid,
EventObj* eventObj = FindEvent(relationship.m_TailGuid);
if (eventObj == nullptr)
{
std::stringstream ss;
ss << "could not find event [" << relationship.m_TailGuid << "]";
ss << " of ExecutionLink [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
// eventClassGuid
EventClassObj* eventClassObj = FindEventClass(relationship.m_AttributeGuid);
if (eventClassObj == nullptr)
{
std::stringstream ss;
ss << "could not find event class [" << relationship.m_TailGuid << "]";
ss << " of ExecutionLink [" << relationship.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
return;
}
eventObj->SetEventClass(eventClassObj);
parentEntity->AddEvent(eventObj);
}
ModelRelationship* TimelineModel::FindRelationship(uint64_t id)
{
auto iter = m_Relationships.find(id);
if (iter != m_Relationships.end())
{
return &(iter->second);
}
else
{
return nullptr;
}
}
bool TimelineModel::IsInferenceGuid(uint64_t guid) const
{
auto it = std::find(m_InferenceGuids.begin(), m_InferenceGuids.end(), guid);
return it != m_InferenceGuids.end();
}
void TimelineModel::AddEventClass(const arm::pipe::ITimelineDecoder::EventClass& eventClass)
{
std::string* eventClassName = FindLabel(eventClass.m_NameGuid);
if (eventClassName != nullptr)
{
EventClassObj eventClassObj(eventClass.m_Guid, *eventClassName);
m_EventClasses.emplace(eventClassObj.GetGuid(), eventClassObj);
}
else
{
std::stringstream ss;
ss << "could not find name [" << eventClass.m_NameGuid << "]";
ss << " of of event class [" << eventClass.m_Guid << "]";
m_Errors.push_back(arm::pipe::ProfilingException(ss.str()));
}
}
EventClassObj* TimelineModel::FindEventClass(uint64_t id)
{
auto iter = m_EventClasses.find(id);
if (iter != m_EventClasses.end())
{
return &(iter->second);
}
else
{
return nullptr;
}
}
void TimelineModel::AddEvent(const arm::pipe::ITimelineDecoder::Event& event)
{
EventObj evt(event.m_Guid, event.m_TimeStamp, event.m_ThreadId);
m_Events.emplace(event.m_Guid, evt);
}
EventObj* TimelineModel::FindEvent(uint64_t id)
{
auto iter = m_Events.find(id);
if (iter != m_Events.end())
{
return &(iter->second);
}
else
{
return nullptr;
}
}
std::vector<std::string> GetModelDescription(const TimelineModel& model)
{
std::vector<std::string> desc;
for (auto& entry : model.GetEntities())
{
auto& entity = entry.second;
desc.push_back(GetEntityDescription(entity));
for (auto& connection : entity.GetConnections())
{
desc.push_back(GetConnectionDescription(connection));
}
for (auto child : entity.GetChildren())
{
desc.push_back(GetChildDescription(child));
}
for (auto execution : entity.GetExecutions())
{
desc.push_back(GetExecutionDescription(execution));
}
for (auto event : entity.GetEvents())
{
desc.push_back(GetEventDescription(event));
}
}
return desc;
}
std::string GetEntityDescription(const Entity& entity)
{
std::stringstream ss;
ss << "Entity [" << entity.GetGuid() << "]";
for (auto& attributeEntry : entity.GetAttributes())
{
if (LabelsAndEventClasses::PROCESS_ID_LABEL == attributeEntry.second.first)
{
ss << " " << attributeEntry.second.first << " = [processId]";
}
else {
ss << " " << attributeEntry.second.first << " = " << attributeEntry.second.second;
}
}
return ss.str();
}
std::string GetChildDescription(Entity* entity)
{
std::stringstream ss;
ss << " child: " << GetEntityDescription(*entity);
return ss.str();
}
std::string GetConnectionDescription(const Connection& connection)
{
std::stringstream ss;
ss << " connection [" << connection.GetGuid() << "] from entity [";
ss << connection.GetHead()->GetGuid() << "] to entity [" << connection.GetTail()->GetGuid() << "]";
return ss.str();
}
std::string GetExecutionDescription(Entity* execution)
{
std::stringstream ss;
ss << " execution: " << GetEntityDescription(*execution);
return ss.str();
}
std::string GetEventDescription(EventObj* event)
{
std::stringstream ss;
ss << " event: [" << event->GetGuid() << "] class [" << event->GetEventClass() << "]";
return ss.str();
}
} // namespace pipe
} // namespace arm