1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
// Copyright Epic Games, Inc. All Rights Reserved.
#include "timeline_query.h"
#include <algorithm>
namespace zen::trace_detail {
namespace {
// Pick the LOD level a given resolution should read from. Mirrors the
// historical selection in trace_viewer_service.cpp: resolution 0 reads the
// raw LOD 0; otherwise the smallest LOD whose ResolutionUs >= the request
// wins, falling back to the coarsest level if none qualify.
//
// Returned values: 0 == raw scopes (LOD 0), 1..kTimelineLodCount == DetailLevels[lod-1].
size_t SelectLodIndex(uint32_t ResolutionUs)
{
if (ResolutionUs == 0)
{
return 0;
}
for (size_t I = 0; I < kTimelineLodCount; ++I)
{
if (kTimelineLodResolutions[I] >= ResolutionUs)
{
return I + 1;
}
}
return kTimelineLodCount;
}
const eastl::vector<TimelineScope>& LodScopes(const ThreadTimeline& Timeline, size_t LodIndex)
{
if (LodIndex == 0)
{
return Timeline.Scopes;
}
return Timeline.DetailLevels[LodIndex - 1].Scopes;
}
void ExtractScopesInto(const ThreadTimeline& Timeline, const TimelineQueryRequest& Req, std::vector<TimelineScopeView>& Out)
{
const eastl::vector<TimelineScope>& Scopes = LodScopes(Timeline, SelectLodIndex(Req.ResolutionUs));
auto MidIt =
std::lower_bound(Scopes.begin(), Scopes.end(), Req.StartUs, [](const TimelineScope& S, uint32_t V) { return S.BeginUs < V; });
for (auto It = Scopes.begin(); It != MidIt; ++It)
{
if ((It->BeginUs + It->DurationUs) < Req.StartUs || It->DurationUs < Req.MinDurUs)
{
continue;
}
Out.push_back({It->BeginUs, It->DurationUs, It->NameId, It->Depth, It->MergeCount});
}
for (auto It = MidIt; It != Scopes.end(); ++It)
{
if (It->BeginUs > Req.EndUs)
{
break;
}
if (It->DurationUs < Req.MinDurUs)
{
continue;
}
Out.push_back({It->BeginUs, It->DurationUs, It->NameId, It->Depth, It->MergeCount});
}
}
const ThreadTimeline* FindThread(const TraceModel& Model, uint32_t ThreadId)
{
auto It = std::find_if(Model.Timelines.begin(), Model.Timelines.end(), [ThreadId](const ThreadTimeline& T) {
return T.ThreadId == ThreadId;
});
return (It != Model.Timelines.end()) ? &*It : nullptr;
}
class InMemoryTimelineQuery final : public TimelineQuery
{
public:
explicit InMemoryTimelineQuery(const TraceModel& Model) : m_Model(Model) {}
void QueryThread(uint32_t ThreadId, const TimelineQueryRequest& Req, std::vector<TimelineScopeView>& Out) const override
{
const ThreadTimeline* Timeline = FindThread(m_Model, ThreadId);
if (Timeline)
{
ExtractScopesInto(*Timeline, Req, Out);
}
}
void QueryBatch(std::span<const uint32_t> ThreadIds, const TimelineQueryRequest& Req, BatchResult& Out) const override
{
Out.Scopes.clear();
Out.Ranges.clear();
Out.Ranges.reserve(ThreadIds.size());
for (uint32_t ThreadId : ThreadIds)
{
const uint32_t Begin = uint32_t(Out.Scopes.size());
const ThreadTimeline* Timeline = FindThread(m_Model, ThreadId);
if (Timeline)
{
ExtractScopesInto(*Timeline, Req, Out.Scopes);
}
Out.Ranges.push_back({Begin, uint32_t(Out.Scopes.size())});
}
}
private:
const TraceModel& m_Model;
};
} // namespace
std::unique_ptr<TimelineQuery>
MakeInMemoryTimelineQuery(const TraceModel& Model)
{
return std::make_unique<InMemoryTimelineQuery>(Model);
}
} // namespace zen::trace_detail
|