/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "Woodpecker_precompiled.h" #include "StreamerDataAggregator.hxx" #include #include "StreamerDrillerDialog.hxx" #include "StreamerEvents.h" #include #include #include "Woodpecker/Driller/Workspaces/Workspace.h" #include #include namespace Driller { class StreamerDataAggregatorSavedState : public AZ::UserSettings { public: AZ_RTTI(StreamerDataAggregatorSavedState, "{0174A3EE-C555-482F-9E7B-7D67D9B4B0A7}", AZ::UserSettings); AZ_CLASS_ALLOCATOR(StreamerDataAggregatorSavedState, AZ::SystemAllocator, 0); StreamerDataAggregatorSavedState() {} static void Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serialize = azrtti_cast(context); if (serialize) { serialize->Class() ->Version(1) ; } } }; // WORKSPACES are files loaded and stored independent of the global application // designed to be used for DRL data specific view settings and to pass around class StreamerDataAggregatorWorkspace : public AZ::UserSettings { public: AZ_RTTI(StreamerDataAggregatorWorkspace, "{D35E8CCA-6FA7-47F6-8A24-8E12EF237E40}", AZ::UserSettings); AZ_CLASS_ALLOCATOR(StreamerDataAggregatorWorkspace, AZ::SystemAllocator, 0); int m_activeViewCount; AZStd::vector m_activeViewTypes; StreamerDataAggregatorWorkspace() : m_activeViewCount(0) {} static void Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serialize = azrtti_cast(context); if (serialize) { serialize->Class() ->Field("m_activeViewCount", &StreamerDataAggregatorWorkspace::m_activeViewCount) ->Field("m_activeViewTypes", &StreamerDataAggregatorWorkspace::m_activeViewTypes) ->Version(1); } } }; ////////////////////////////////////////////////////////////////////////// StreamerDataAggregator::StreamerDataAggregator(int identity) : Aggregator(identity) , m_activeViewCount(0) , m_highwaterFrame(-1) { m_parser.SetAggregator(this); ResetTrackingInfo(); } StreamerDataAggregator::~StreamerDataAggregator() { KillAllViews(); } // gross generalization of activity based on total number of all events this frame float StreamerDataAggregator::ValueAtFrame(FrameNumberType frame) { const float maxEventsPerFrame = 10.0f; // just a scale number float numEventsPerFrame = static_cast(NumOfEventsAtFrame(frame)); return AZStd::GetMin(numEventsPerFrame / maxEventsPerFrame, 1.0f) * 2.0f - 1.0f; } QColor StreamerDataAggregator::GetColor() const { return QColor(0, 255, 255); } QString StreamerDataAggregator::GetName() const { return "Streamer"; } QString StreamerDataAggregator::GetChannelName() const { return ChannelName(); } QString StreamerDataAggregator::GetDescription() const { return "Streamer events driller"; } QString StreamerDataAggregator::GetToolTip() const { return "Streamer Events"; } AZ::Uuid StreamerDataAggregator::GetID() const { return AZ::Uuid("{9A2854C8-8106-4075-9287-3E047821D934}"); } QWidget* StreamerDataAggregator::DrillDownRequest(FrameNumberType frame) { StreamerDrillerDialog* dialog = NULL; AZ::u32 availableIdx = 0; bool foundASpot = true; do { foundASpot = true; for (DataViewMap::iterator iter = m_dataViews.begin(); iter != m_dataViews.end(); ++iter) { if (iter->second == availableIdx) { foundASpot = false; ++availableIdx; break; } } } while (!foundASpot); dialog = aznew StreamerDrillerDialog(this, frame, (1024 * GetIdentity()) + availableIdx); if (dialog) { m_dataViews[dialog] = availableIdx; connect(dialog, SIGNAL(destroyed(QObject*)), this, SLOT(OnDataViewDestroyed(QObject*))); ++m_activeViewCount; } return dialog; } QWidget* StreamerDataAggregator::DrillDownRequest(FrameNumberType frame, int type) { StreamerDrillerDialog* view = static_cast(DrillDownRequest(frame)); if (view) { view->SetChartType(type); } return view; } void StreamerDataAggregator::OptionsRequest() { QMenu* popupMenu = new QMenu(); QMenu* cachedHitsTypeMenu = new QMenu(tr("Cached Hits")); cachedHitsTypeMenu->addAction(tr("Do Not Report Cache Hits")); cachedHitsTypeMenu->addAction(tr("Report Cache Hits")); popupMenu->addMenu(cachedHitsTypeMenu); QAction* act = cachedHitsTypeMenu->exec(QCursor::pos()); if (act) { if (act->text() == tr("Report Cache Hits")) { m_parser.AllowCacheHitsInReportedStream(true); } if (act->text() == tr("Do Not Report Cache Hits")) { m_parser.AllowCacheHitsInReportedStream(false); } } } void StreamerDataAggregator::OnDataViewDestroyed(QObject* dataView) { m_dataViews.erase(dataView); --m_activeViewCount; } void StreamerDataAggregator::KillAllViews() { do { DataViewMap::iterator iter = m_dataViews.begin(); if (iter != m_dataViews.end()) { delete iter->first; continue; } break; } while (1); } void StreamerDataAggregator::ApplySettingsFromWorkspace(WorkspaceSettingsProvider* provider) { StreamerDataAggregatorWorkspace* workspace = provider->FindSetting(AZ_CRC("STREAMER DATA AGGREGATOR WORKSPACE", 0x105be192)); if (workspace) { m_activeViewCount = workspace->m_activeViewCount; } } void StreamerDataAggregator::ActivateWorkspaceSettings(WorkspaceSettingsProvider* provider) { StreamerDataAggregatorWorkspace* workspace = provider->FindSetting(AZ_CRC("STREAMER DATA AGGREGATOR WORKSPACE", 0x105be192)); if (workspace) { // kill all existing data view windows in preparation of opening the workspace specified ones KillAllViews(); // the internal count should be 0 from the above house cleaning // and incremented back up from the workspace instantiations m_activeViewCount = 0; for (int i = 0; i < workspace->m_activeViewCount; ++i) { //// start this check to default int discoveredType = 0; if (workspace->m_activeViewTypes.size() > i) { discoveredType = workspace->m_activeViewTypes[i]; } Driller::StreamerDrillerDialog* dataView = qobject_cast(DrillDownRequest(1, discoveredType)); if (dataView) { // apply will overlay the workspace settings on top of the local user settings dataView->ApplySettingsFromWorkspace(provider); // activate will do the heavy lifting dataView->ActivateWorkspaceSettings(provider); } } } } void StreamerDataAggregator::SaveSettingsToWorkspace(WorkspaceSettingsProvider* provider) { StreamerDataAggregatorWorkspace* workspace = provider->CreateSetting(AZ_CRC("STREAMER DATA AGGREGATOR WORKSPACE", 0x105be192)); if (workspace) { workspace->m_activeViewTypes.clear(); workspace->m_activeViewCount = m_activeViewCount; for (DataViewMap::iterator iter = m_dataViews.begin(); iter != m_dataViews.end(); ++iter) { Driller::StreamerDrillerDialog* dataView = qobject_cast(iter->first); if (dataView) { workspace->m_activeViewTypes.push_back(dataView->GetViewType()); dataView->SaveSettingsToWorkspace(provider); } } } } //========================================================================= // Reset // [7/10/2013] //========================================================================= void StreamerDataAggregator::Reset() { m_devices.clear(); m_streams.clear(); m_requests.clear(); m_seeksInfo.clear(); ResetTrackingInfo(); } void StreamerDataAggregator::ResetTrackingInfo() { m_seekTracking.clear(); m_highwaterFrame = -1; // default device with ID := 0 SeekTrackingInfo seekTrackingInfo; seekTrackingInfo.m_currentStreamId = 0; seekTrackingInfo.m_offset = 0; m_seekTracking.insert(AZStd::make_pair(0, seekTrackingInfo)); } void StreamerDataAggregator::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serialize = azrtti_cast(context); if (serialize) { StreamerDataAggregatorSavedState::Reflect(context); StreamerDataAggregatorWorkspace::Reflect(context); StreamerDrillerDialog::Reflect(context); serialize->Class() ->Version(1) ; } } void StreamerDataAggregator::AdvanceToFrame(FrameNumberType frame) { while (m_highwaterFrame < frame) { ++m_highwaterFrame; FrameChanged(m_highwaterFrame); m_frameInfo.push_back(); m_frameInfo.back().m_computedSeeksCount = 0; m_frameInfo.back().m_computedThroughput = 0; AZ::s64 numEvents = NumOfEventsAtFrame(m_highwaterFrame); if (numEvents) { AZ::s64 firstIndex = GetFirstIndexAtFrame(m_highwaterFrame); for (AZ::s64 idx = 0; idx < numEvents; ++idx) { DrillerEvent* dep = m_events[ idx + firstIndex ]; AZ::u64 geid = dep->GetGlobalEventId(); switch (dep->GetEventType()) { case Driller::Streamer::SET_DEVICE_MOUNTED: { SeekTrackingInfo seekTrackingInfo; seekTrackingInfo.m_currentStreamId = 0; seekTrackingInfo.m_offset = 0; m_seekTracking.insert(AZStd::make_pair(static_cast(dep)->m_deviceData.m_id, seekTrackingInfo)); break; } case Driller::Streamer::SET_DEVICE_UNMOUNTED: { m_seekTracking.erase(static_cast(dep)->m_unmountedDeviceData->m_id); break; } case Driller::Streamer::SET_ADD_REQUEST: { break; } case Driller::Streamer::SET_CANCEL_REQUEST: case Driller::Streamer::SET_RESCHEDULE_REQUEST: case Driller::Streamer::SET_COMPLETE_REQUEST: { break; } case Driller::Streamer::SET_REGISTER_STREAM: case Driller::Streamer::SET_UNREGISTER_STREAM: { break; } // m_stream := possibly NULL in these two cases case Driller::Streamer::SET_OPERATION_START: { auto depEvt = static_cast(dep); if (depEvt->m_stream) { auto trackedDevice = m_seekTracking.find(depEvt->m_stream->m_deviceId); if (trackedDevice == m_seekTracking.end()) { SeekTrackingInfo seekTrackingInfo; seekTrackingInfo.m_currentStreamId = 0; seekTrackingInfo.m_offset = 0; m_seekTracking.insert(AZStd::make_pair(depEvt->m_stream->m_deviceId, seekTrackingInfo)); trackedDevice = m_seekTracking.find(depEvt->m_stream->m_deviceId); } // reasons a device might SEEK if (trackedDevice->second.m_currentStreamId != depEvt->m_streamId) { if ( (depEvt->m_stream->m_isCompressed && depEvt->m_operation.m_type == Streamer::SOP_COMPRESSOR_READ) || (!depEvt->m_stream->m_isCompressed) ) { m_frameInfo.back().m_seekInfo.push_back(); m_frameInfo.back().m_seekInfo.back().m_eventId = geid; m_frameInfo.back().m_seekInfo.back().m_eventReason = SEEK_EVENT_SWITCH; trackedDevice->second.m_currentStreamId = depEvt->m_streamId; trackedDevice->second.m_offset = depEvt->m_operation.m_offset; ++m_frameInfo.back().m_computedSeeksCount; m_seeksInfo.insert(AZStd::make_pair(geid, SEEK_EVENT_SWITCH)); } } else if (trackedDevice->second.m_offset != depEvt->m_operation.m_offset) { if ( (depEvt->m_stream->m_isCompressed && depEvt->m_operation.m_type == Streamer::SOP_COMPRESSOR_READ) || (!depEvt->m_stream->m_isCompressed) ) { m_frameInfo.back().m_seekInfo.push_back(); m_frameInfo.back().m_seekInfo.back().m_eventId = geid; m_frameInfo.back().m_seekInfo.back().m_eventReason = SEEK_EVENT_SKIP; trackedDevice->second.m_offset = depEvt->m_operation.m_offset; ++m_frameInfo.back().m_computedSeeksCount; m_seeksInfo.insert(AZStd::make_pair(geid, SEEK_EVENT_SKIP)); } } } break; } case Driller::Streamer::SET_OPERATION_COMPLETE: { auto depEvt = azdynamic_cast(dep); if (depEvt->m_stream) { m_frameInfo.back().m_transferInfo.push_back(); m_frameInfo.back().m_transferInfo.back().m_eventId = geid; m_frameInfo.back().m_transferInfo.back().m_eventReason = (TransferEventType)(depEvt->m_type); auto trackedDevice = m_seekTracking.find(depEvt->m_stream->m_deviceId); if (trackedDevice == m_seekTracking.end()) { SeekTrackingInfo seekTrackingInfo; seekTrackingInfo.m_currentStreamId = 0; seekTrackingInfo.m_offset = 0; m_seekTracking.insert(AZStd::make_pair(depEvt->m_stream->m_deviceId, seekTrackingInfo)); trackedDevice = m_seekTracking.find(depEvt->m_stream->m_deviceId); } if (depEvt->m_stream->m_isCompressed) { if (static_cast(depEvt->m_type) == TRANSFER_EVENT_COMPRESSOR_READ || static_cast(depEvt->m_type) == TRANSFER_EVENT_COMPRESSOR_WRITE) { m_frameInfo.back().m_transferInfo.back().m_byteCount = depEvt->m_bytesTransferred; m_frameInfo.back().m_computedThroughput += depEvt->m_bytesTransferred; trackedDevice->second.m_offset += depEvt->m_bytesTransferred; } } else { m_frameInfo.back().m_transferInfo.back().m_byteCount = depEvt->m_bytesTransferred; m_frameInfo.back().m_computedThroughput += depEvt->m_bytesTransferred; trackedDevice->second.m_offset += depEvt->m_bytesTransferred; } } break; } } } } } } const char* StreamerDataAggregator::GetFilenameFromStreamId(unsigned int globalEventId, AZ::u64 streamId) { // starting at eventId, skip backwards through the events until a register stream is found while (1) { if (globalEventId > m_events.size()) { break; } auto event = m_events[globalEventId]; auto registerEvent = azdynamic_cast(event); if (registerEvent && registerEvent->m_streamData.m_id == streamId) { return registerEvent->m_streamData.m_name; } if (globalEventId == 0) { break; } --globalEventId; } return ""; } const char* StreamerDataAggregator::GetDebugNameFromStreamId(unsigned int globalEventId, AZ::u64 streamId) { // starting at eventId, skip backwards through the events until a request added (which has debug info) is found while (1) { if (globalEventId > m_events.size()) { break; } auto event = m_events[globalEventId]; auto requestEvent = azdynamic_cast(event); if (requestEvent && requestEvent->m_requestData.m_streamId == streamId) { if (requestEvent->m_requestData.m_debugName) { return requestEvent->m_requestData.m_debugName; } else { return ""; } } if (globalEventId == 0) { break; } --globalEventId; } return ""; } const AZ::u64 StreamerDataAggregator::GetOffsetFromStreamId(unsigned int globalEventId, AZ::u64 streamId) { // starting at eventId, skip backwards through the events until the start operation related to this ID is found while (1) { if (globalEventId > m_events.size()) { break; } auto event = m_events[globalEventId]; auto startEvent = azdynamic_cast(event); if (startEvent && startEvent->m_streamId == streamId) { return startEvent->m_operation.m_offset; } if (globalEventId == 0) { break; } --globalEventId; } return 0; } float StreamerDataAggregator::ThroughputAtFrame(FrameNumberType frame) { if (frame >= 0) { AdvanceToFrame(frame); return (float)m_frameInfo[frame].m_computedThroughput; } return 0.0f; } float StreamerDataAggregator::SeeksAtFrame(FrameNumberType frame) { if (frame >= 0) { AdvanceToFrame(frame); return (float)m_frameInfo[frame].m_computedSeeksCount; } return 0.0f; } Driller::StreamerDataAggregator::TransferBreakoutType& StreamerDataAggregator::ThroughputAtFrameBreakout(FrameNumberType frame) { AdvanceToFrame(frame); return m_frameInfo[frame].m_transferInfo; } Driller::StreamerDataAggregator::SeeksBreakoutType& StreamerDataAggregator::SeeksAtFrameBreakout(FrameNumberType frame) { AdvanceToFrame(frame); return m_frameInfo[frame].m_seekInfo; } StreamerDataAggregator::SeekEventType StreamerDataAggregator::GetSeekType(AZ::s64 id) { auto iter = m_seeksInfo.find(id); if (iter != m_seeksInfo.end()) { return iter->second; } return SEEK_EVENT_NONE; } } // namespace Driller