1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "src/trace_processor/importers/proto/perf_sample_tracker.h"
17
18 #include <stdio.h>
19
20 #include <cinttypes>
21
22 #include "perfetto/ext/base/string_utils.h"
23 #include "src/trace_processor/importers/common/track_tracker.h"
24 #include "src/trace_processor/storage/trace_storage.h"
25 #include "src/trace_processor/types/trace_processor_context.h"
26
27 #include "protos/perfetto/common/perf_events.pbzero.h"
28 #include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
29 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
30
31 namespace perfetto {
32 namespace trace_processor {
33
34 namespace {
35 // Follow perf tool naming convention.
StringifyCounter(int32_t counter)36 const char* StringifyCounter(int32_t counter) {
37 using protos::pbzero::PerfEvents;
38 switch (counter) {
39 // software:
40 case PerfEvents::SW_CPU_CLOCK:
41 return "cpu-clock";
42 case PerfEvents::SW_PAGE_FAULTS:
43 return "page-faults";
44 case PerfEvents::SW_TASK_CLOCK:
45 return "task-clock";
46 case PerfEvents::SW_CONTEXT_SWITCHES:
47 return "context-switches";
48 case PerfEvents::SW_CPU_MIGRATIONS:
49 return "cpu-migrations";
50 case PerfEvents::SW_PAGE_FAULTS_MIN:
51 return "minor-faults";
52 case PerfEvents::SW_PAGE_FAULTS_MAJ:
53 return "major-faults";
54 case PerfEvents::SW_ALIGNMENT_FAULTS:
55 return "alignment-faults";
56 case PerfEvents::SW_EMULATION_FAULTS:
57 return "emulation-faults";
58 case PerfEvents::SW_DUMMY:
59 return "dummy";
60 // hardware:
61 case PerfEvents::HW_CPU_CYCLES:
62 return "cpu-cycles";
63 case PerfEvents::HW_INSTRUCTIONS:
64 return "instructions";
65 case PerfEvents::HW_CACHE_REFERENCES:
66 return "cache-references";
67 case PerfEvents::HW_CACHE_MISSES:
68 return "cache-misses";
69 case PerfEvents::HW_BRANCH_INSTRUCTIONS:
70 return "branch-instructions";
71 case PerfEvents::HW_BRANCH_MISSES:
72 return "branch-misses";
73 case PerfEvents::HW_BUS_CYCLES:
74 return "bus-cycles";
75 case PerfEvents::HW_STALLED_CYCLES_FRONTEND:
76 return "stalled-cycles-frontend";
77 case PerfEvents::HW_STALLED_CYCLES_BACKEND:
78 return "stalled-cycles-backend";
79 case PerfEvents::HW_REF_CPU_CYCLES:
80 return "ref-cycles";
81
82 default:
83 break;
84 }
85 PERFETTO_DLOG("Unknown PerfEvents::Counter enum value");
86 return "unknown";
87 }
88
InternTimebaseCounterName(protos::pbzero::TracePacketDefaults::Decoder * defaults,TraceProcessorContext * context)89 StringId InternTimebaseCounterName(
90 protos::pbzero::TracePacketDefaults::Decoder* defaults,
91 TraceProcessorContext* context) {
92 using namespace protos::pbzero;
93 PerfSampleDefaults::Decoder perf_defaults(defaults->perf_sample_defaults());
94 PerfEvents::Timebase::Decoder timebase(perf_defaults.timebase());
95
96 auto config_given_name = timebase.name();
97 if (config_given_name.size > 0) {
98 return context->storage->InternString(config_given_name);
99 }
100 if (timebase.has_counter()) {
101 return context->storage->InternString(StringifyCounter(timebase.counter()));
102 }
103 if (timebase.has_tracepoint()) {
104 PerfEvents::Tracepoint::Decoder tracepoint(timebase.tracepoint());
105 return context->storage->InternString(tracepoint.name());
106 }
107 if (timebase.has_raw_event()) {
108 PerfEvents::RawEvent::Decoder raw(timebase.raw_event());
109 // This doesn't follow any pre-existing naming scheme, but aims to be a
110 // short-enough default that is distinguishable.
111 base::StackString<128> name(
112 "raw.0x%" PRIx32 ".0x%" PRIx64 ".0x%" PRIx64 ".0x%" PRIx64, raw.type(),
113 raw.config(), raw.config1(), raw.config2());
114 return context->storage->InternString(name.string_view());
115 }
116
117 PERFETTO_DLOG("Could not name the perf timebase counter");
118 return context->storage->InternString("unknown");
119 }
120 } // namespace
121
GetSamplingStreamInfo(uint32_t seq_id,uint32_t cpu,protos::pbzero::TracePacketDefaults::Decoder * nullable_defaults)122 PerfSampleTracker::SamplingStreamInfo PerfSampleTracker::GetSamplingStreamInfo(
123 uint32_t seq_id,
124 uint32_t cpu,
125 protos::pbzero::TracePacketDefaults::Decoder* nullable_defaults) {
126 auto seq_it = seq_state_.find(seq_id);
127 if (seq_it == seq_state_.end()) {
128 seq_it = seq_state_.emplace(seq_id, next_perf_session_id_++).first;
129 }
130 SequenceState* seq_state = &seq_it->second;
131 uint32_t session_id = seq_state->perf_session_id;
132
133 auto cpu_it = seq_state->per_cpu.find(cpu);
134 if (cpu_it != seq_state->per_cpu.end())
135 return {seq_state->perf_session_id, cpu_it->second.timebase_track_id};
136
137 // No defaults means legacy producer implementation, assume default timebase
138 // of per-cpu timer. Always the case for Android R builds, and it isn't worth
139 // guaranteeing support for intermediate S builds in this aspect.
140 StringId name_id = kNullStringId;
141 if (!nullable_defaults || !nullable_defaults->has_perf_sample_defaults()) {
142 name_id = context_->storage->InternString(
143 StringifyCounter(protos::pbzero::PerfEvents::SW_CPU_CLOCK));
144 } else {
145 name_id = InternTimebaseCounterName(nullable_defaults, context_);
146 }
147
148 TrackId timebase_track_id = context_->track_tracker->CreatePerfCounterTrack(
149 name_id, session_id, cpu, /*is_timebase=*/true);
150
151 seq_state->per_cpu.emplace(cpu, timebase_track_id);
152
153 return {session_id, timebase_track_id};
154 }
155
156 } // namespace trace_processor
157 } // namespace perfetto
158