Merge changes Ic1c3e077,I69b8ec0d into main
* changes:
ui: Use plugin deps to add tracks to process groups
ui: Don't render tracks while the trace is loading
diff --git a/src/trace_processor/importers/common/track_tracker.cc b/src/trace_processor/importers/common/track_tracker.cc
index 6b02ff8..79bca11 100644
--- a/src/trace_processor/importers/common/track_tracker.cc
+++ b/src/trace_processor/importers/common/track_tracker.cc
@@ -464,40 +464,6 @@
return track_id;
}
-TrackId TrackTracker::LegacyInternCpuIdleStateTrack(uint32_t cpu,
- StringId state) {
- auto ucpu = context_->cpu_tracker->GetOrCreateCpu(cpu);
- DimensionsBuilder dims_builder = CreateDimensionsBuilder();
- dims_builder.AppendDimension(
- context_->storage->InternString("cpu_idle_state"),
- Variadic::String(state));
- dims_builder.AppendUcpu(ucpu);
- Dimensions dims_id = std::move(dims_builder).Build();
-
- tracks::TrackClassification classification = tracks::cpu_idle_state;
-
- auto* it = tracks_.Find({classification, dims_id});
- if (it) {
- return *it;
- }
-
- std::string name =
- "cpuidle." + context_->storage->GetString(state).ToStdString();
-
- tables::CpuCounterTrackTable::Row row(
- context_->storage->InternString(name.c_str()));
- row.ucpu = ucpu;
- row.machine_id = context_->machine_id();
- row.classification =
- context_->storage->InternString(tracks::ToString(classification));
- row.dimension_arg_set_id = dims_id.arg_set_id;
-
- TrackId track_id =
- context_->storage->mutable_cpu_counter_track_table()->Insert(row).id;
- tracks_[{classification, dims_id}] = track_id;
- return track_id;
-}
-
TrackId TrackTracker::InternGpuCounterTrack(
tracks::TrackClassification classification,
uint32_t gpu_id,
diff --git a/src/trace_processor/importers/common/track_tracker.h b/src/trace_processor/importers/common/track_tracker.h
index d4d14f0..3736272 100644
--- a/src/trace_processor/importers/common/track_tracker.h
+++ b/src/trace_processor/importers/common/track_tracker.h
@@ -247,8 +247,6 @@
bool trace_id_is_process_scoped,
StringId source_scope);
- TrackId LegacyInternCpuIdleStateTrack(uint32_t cpu, StringId state);
-
TrackId LegacyCreateGpuCounterTrack(StringId name,
uint32_t gpu_id,
StringId description = StringId::Null(),
diff --git a/src/trace_processor/importers/proto/system_probes_parser.cc b/src/trace_processor/importers/proto/system_probes_parser.cc
index 08212a8..574653a 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.cc
+++ b/src/trace_processor/importers/proto/system_probes_parser.cc
@@ -166,6 +166,7 @@
gpufreq_id(context->storage->InternString("gpufreq")),
gpufreq_unit_id(context->storage->InternString("MHz")),
cpu_stat_counter_name_id_(context->storage->InternString("counter_name")),
+ cpu_idle_state_id_(context_->storage->InternString("cpu_idle_state")),
arm_cpu_implementer(
context->storage->InternString("arm_cpu_implementer")),
arm_cpu_architecture(
@@ -526,12 +527,20 @@
void SystemProbesParser::ParseCpuIdleStats(int64_t ts, ConstBytes blob) {
protos::pbzero::SysStats::CpuIdleState::Decoder cpuidle_state(blob);
uint32_t cpu_id = cpuidle_state.cpu_id();
+ auto ucpu = context_->cpu_tracker->GetOrCreateCpu(cpu_id);
for (auto cpuidle_field = cpuidle_state.cpuidle_state_entry(); cpuidle_field;
++cpuidle_field) {
protos::pbzero::SysStats::CpuIdleStateEntry::Decoder idle(*cpuidle_field);
- TrackId track = context_->track_tracker->LegacyInternCpuIdleStateTrack(
- cpu_id, context_->storage->InternString(idle.state()));
+ TrackTracker::DimensionsBuilder dims_builder =
+ context_->track_tracker->CreateDimensionsBuilder();
+ dims_builder.AppendDimension(
+ cpu_idle_state_id_,
+ Variadic::String(context_->storage->InternString(idle.state())));
+ dims_builder.AppendUcpu(ucpu);
+ TrackId track = context_->track_tracker->InternTrack(
+ tracks::cpu_idle_state, std::move(dims_builder).Build());
+
context_->event_tracker->PushCounter(
ts, static_cast<double>(idle.duration_us()), track);
}
diff --git a/src/trace_processor/importers/proto/system_probes_parser.h b/src/trace_processor/importers/proto/system_probes_parser.h
index 87b5734..1db4b65 100644
--- a/src/trace_processor/importers/proto/system_probes_parser.h
+++ b/src/trace_processor/importers/proto/system_probes_parser.h
@@ -67,6 +67,8 @@
const StringId cpu_stat_counter_name_id_;
+ const StringId cpu_idle_state_id_;
+
// Arm CPU identifier string IDs
const StringId arm_cpu_implementer;
const StringId arm_cpu_architecture;
diff --git a/src/trace_processor/perfetto_sql/stdlib/linux/cpu/idle_time_in_state.sql b/src/trace_processor/perfetto_sql/stdlib/linux/cpu/idle_time_in_state.sql
index 8bff4b3..5a4298e 100644
--- a/src/trace_processor/perfetto_sql/stdlib/linux/cpu/idle_time_in_state.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/linux/cpu/idle_time_in_state.sql
@@ -21,6 +21,8 @@
CREATE PERFETTO TABLE cpu_idle_time_in_state_counters(
-- Timestamp.
ts LONG,
+ -- The machine this residency is calculated for.
+ machine_id LONG,
-- State name.
state_name STRING,
-- Percentage of time all CPUS spent in this state.
@@ -30,31 +32,51 @@
-- Time all CPUS spent in any state, in microseconds.
time_slice INT
) AS
-WITH residency_deltas AS (
+WITH cpu_counts_per_machine AS (
+ SELECT machine_id, count(1) AS cpu_count
+ FROM cpu
+ GROUP BY machine_id
+),
+idle_states AS (
SELECT
- ts,
- c.name as state_name,
- value - (LAG(value) OVER (PARTITION BY c.name, cct.cpu ORDER BY ts)) as delta
- FROM counters c
- JOIN cpu_counter_track cct on c.track_id=cct.id
- WHERE c.name GLOB 'cpuidle.*'
+ c.ts,
+ c.value,
+ EXTRACT_ARG(t.dimension_arg_set_id, 'cpu_idle_state') as state,
+ EXTRACT_ARG(t.dimension_arg_set_id, 'ucpu') as ucpu
+ FROM counter c
+ JOIN track t on c.track_id = t.id
+ WHERE t.classification = 'cpu_idle_state'
+),
+residency_deltas AS (
+ SELECT
+ ts,
+ state,
+ ucpu,
+ value - (LAG(value) OVER (PARTITION BY state, ucpu ORDER BY ts)) as delta
+ FROM idle_states
),
total_residency_calc AS (
-SELECT
- ts,
- state_name,
- sum(delta) as total_residency,
- -- Perfetto timestamp is in nanoseconds whereas sysfs cpuidle time
- -- is in microseconds.
- (
- (SELECT count(distinct cpu) from cpu_counter_track) *
- (time_to_us(ts - LAG(ts,1) over (partition by state_name order by ts)))
- ) as time_slice
+ SELECT
+ ts,
+ cpu.machine_id,
+ state AS state_name,
+ SUM(delta) as total_residency,
+ -- Perfetto timestamp is in nanoseconds whereas sysfs cpuidle time
+ -- is in microseconds.
+ (
+ cpu_counts_per_machine.cpu_count *
+ (time_to_us(ts - LAG(ts, 1) over (PARTITION BY state ORDER BY ts)))
+ ) as time_slice
FROM residency_deltas
-GROUP BY ts, state_name
+ JOIN cpu USING (ucpu)
+ -- The use of `IS` instead of `=` is intentional because machine_id can be
+ -- null and we still want this join to work in that case.
+ JOIN cpu_counts_per_machine ON cpu.machine_id IS cpu_counts_per_machine.machine_id
+ GROUP BY ts, cpu.machine_id, state
)
SELECT
ts,
+ machine_id,
state_name,
MIN(100, (total_residency / time_slice) * 100) as idle_percentage,
total_residency,
@@ -65,7 +87,8 @@
-- Calculate c0 state by subtracting all other states from total time.
SELECT
ts,
- 'cpuidle.C0' as state_name,
+ machine_id,
+ 'C0' as state_name,
(MAX(0,time_slice - SUM(total_residency)) / time_slice) * 100 AS idle_percentage,
time_slice - SUM(total_residency),
time_slice
diff --git a/src/trace_processor/perfetto_sql/stdlib/wattson/curves/w_dsu_dependence.sql b/src/trace_processor/perfetto_sql/stdlib/wattson/curves/w_dsu_dependence.sql
index dbaf4ac..9435c09 100644
--- a/src/trace_processor/perfetto_sql/stdlib/wattson/curves/w_dsu_dependence.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/wattson/curves/w_dsu_dependence.sql
@@ -55,6 +55,22 @@
base.freq_7 = lut7.freq_khz AND
base.idle_7 = lut7.idle;
+-- Get nominal devfreq_dsu counter, OR use a dummy one for Pixel 9 VM traces
+-- The VM doesn't have a DSU, so the placeholder value of FMin is put in. The
+-- DSU frequency is a prerequisite for power estimation on Pixel 9.
+CREATE PERFETTO TABLE _dsu_frequency AS
+SELECT * from linux_devfreq_dsu_counter
+UNION ALL
+SELECT
+ 0 as id,
+ trace_start() as ts,
+ trace_end() - trace_start() as dur,
+ 610000 as dsu_freq
+-- Only add this for traces from a VM on Pixel 9 where DSU values aren't present
+WHERE (SELECT str_value FROM metadata WHERE name = 'android_guest_soc_model')
+ IN (SELECT device FROM _use_devfreq)
+ AND (SELECT COUNT(*) FROM linux_devfreq_dsu_counter) = 0;
+
CREATE PERFETTO TABLE _w_dsu_dependence AS
SELECT
c.ts, c.dur,
@@ -80,10 +96,10 @@
FROM _interval_intersect!(
(
_ii_subquery!(_cpu_curves),
- _ii_subquery!(linux_devfreq_dsu_counter)
+ _ii_subquery!(_dsu_frequency)
),
()
) ii
JOIN _cpu_curves AS c ON c._auto_id = id_0
-JOIN linux_devfreq_dsu_counter AS d on d._auto_id = id_1;
+JOIN _dsu_frequency AS d on d._auto_id = id_1;
diff --git a/test/data/wattson_tk4_vm.pb.sha256 b/test/data/wattson_tk4_vm.pb.sha256
new file mode 100644
index 0000000..52b09dd
--- /dev/null
+++ b/test/data/wattson_tk4_vm.pb.sha256
@@ -0,0 +1 @@
+12beb14bc06e28ecbdfc618d423aeea2badd449aeb9ccc65a457aa6c05ebf2be
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/parser/parsing/tests_sys_stats.py b/test/trace_processor/diff_tests/parser/parsing/tests_sys_stats.py
index 56e2959..ab23e0b 100644
--- a/test/trace_processor/diff_tests/parser/parsing/tests_sys_stats.py
+++ b/test/trace_processor/diff_tests/parser/parsing/tests_sys_stats.py
@@ -50,15 +50,19 @@
}
"""),
query="""
- SELECT ts, cct.name, value, cct.cpu
+ SELECT
+ ts,
+ EXTRACT_ARG(t.dimension_arg_set_id, 'cpu_idle_state') as state,
+ value,
+ EXTRACT_ARG(t.dimension_arg_set_id, 'ucpu') as cpu
FROM counter c
- JOIN cpu_counter_track cct on c.track_id = cct.id
+ JOIN track t on c.track_id = t.id
ORDER BY ts;
""",
out=Csv("""
- "ts","name","value","cpu"
- 71625871363623,"cpuidle.C8",486626084.000000,0
- 71626000387166,"cpuidle.C8",486636254.000000,0
+ "ts","state","value","cpu"
+ 71625871363623,"C8",486626084.000000,0
+ 71626000387166,"C8",486636254.000000,0
"""))
def test_thermal_zones(self):
diff --git a/test/trace_processor/diff_tests/stdlib/linux/cpu.py b/test/trace_processor/diff_tests/stdlib/linux/cpu.py
index 1c38b5b..1783b17 100644
--- a/test/trace_processor/diff_tests/stdlib/linux/cpu.py
+++ b/test/trace_processor/diff_tests/stdlib/linux/cpu.py
@@ -566,9 +566,9 @@
SELECT * FROM cpu_idle_time_in_state_counters;
""",
out=Csv("""
- "ts","state_name","idle_percentage","total_residency","time_slice"
- 200001000000,"cpuidle.C8",10.000000,100.000000,1000
- 200002000000,"cpuidle.C8",10.000000,100.000000,1000
- 200001000000,"cpuidle.C0",90.000000,900.000000,1000
- 200002000000,"cpuidle.C0",90.000000,900.000000,1000
+ "ts","machine_id","state_name","idle_percentage","total_residency","time_slice"
+ 200001000000,"[NULL]","C8",10.000000,100.000000,1000
+ 200002000000,"[NULL]","C8",10.000000,100.000000,1000
+ 200001000000,"[NULL]","C0",90.000000,900.000000,1000
+ 200002000000,"[NULL]","C0",90.000000,900.000000,1000
"""))
diff --git a/test/trace_processor/diff_tests/stdlib/wattson/tests.py b/test/trace_processor/diff_tests/stdlib/wattson/tests.py
index b5c9cae..5b20333 100644
--- a/test/trace_processor/diff_tests/stdlib/wattson/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/wattson/tests.py
@@ -452,3 +452,30 @@
452415394221,69579176303,13654,13361,11651,9609,1
564873995228,135118729231,45223,37594,22798,20132,1
"""))
+
+ # Tests traces from VM that have incomplete CPU tracks
+ def test_wattson_missing_cpus_on_guest(self):
+ return DiffTestBlueprint(
+ trace=DataPath('wattson_tk4_vm.pb'),
+ query=("""
+ INCLUDE PERFETTO MODULE wattson.curves.estimates;
+ SELECT
+ ts, dur, cpu0_mw, cpu1_mw, cpu2_mw, cpu3_mw, cpu4_mw, cpu5_mw,
+ cpu6_mw
+ FROM _system_state_mw
+ WHERE ts > 25150000000
+ LIMIT 10
+ """),
+ out=Csv("""
+ "ts","dur","cpu0_mw","cpu1_mw","cpu2_mw","cpu3_mw","cpu4_mw","cpu5_mw","cpu6_mw"
+ 25150029000,1080,0.000000,0.000000,0.000000,0.000000,70.050000,83.260000,0.000000
+ 25150030640,42920,0.000000,0.000000,0.000000,0.000000,70.050000,70.050000,0.000000
+ 25150073560,99800,0.000000,0.000000,0.000000,0.000000,70.050000,0.000000,0.000000
+ 25150173360,28240,176.280000,0.000000,0.000000,0.000000,70.050000,0.000000,0.000000
+ 25150201600,6480,176.280000,0.000000,0.000000,176.280000,70.050000,0.000000,0.000000
+ 25150208080,29840,176.280000,0.000000,0.000000,176.280000,70.050000,70.050000,0.000000
+ 25150237920,129800,0.000000,0.000000,0.000000,176.280000,70.050000,70.050000,0.000000
+ 25150367720,37480,0.000000,0.000000,0.000000,176.280000,70.050000,0.000000,0.000000
+ 25150405200,15120,0.000000,176.280000,0.000000,176.280000,70.050000,0.000000,0.000000
+ 25150420320,15920,0.000000,176.280000,0.000000,0.000000,70.050000,0.000000,0.000000
+ """))
diff --git a/ui/src/assets/explore_page.scss b/ui/src/assets/explore_page.scss
new file mode 100644
index 0000000..c31b288
--- /dev/null
+++ b/ui/src/assets/explore_page.scss
@@ -0,0 +1,16 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// 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.
+.explore-page {
+ overflow: auto;
+}
diff --git a/ui/src/assets/perfetto.scss b/ui/src/assets/perfetto.scss
index 3e04c42..cb4387d 100644
--- a/ui/src/assets/perfetto.scss
+++ b/ui/src/assets/perfetto.scss
@@ -30,6 +30,7 @@
@import "viz_page";
@import "widgets_page";
@import "plugins_page";
+@import "explore_page";
// Widgets - keep these sorted (they should NOT have any inter-dependencies)
@import "widgets/anchor";
diff --git a/ui/src/plugins/dev.perfetto.CpuidleTimeInState/index.ts b/ui/src/plugins/dev.perfetto.CpuidleTimeInState/index.ts
index 3e4aaa1..e180585 100644
--- a/ui/src/plugins/dev.perfetto.CpuidleTimeInState/index.ts
+++ b/ui/src/plugins/dev.perfetto.CpuidleTimeInState/index.ts
@@ -65,11 +65,13 @@
this.addCounterTrack(
ctx,
it.state_name,
- `select
+ `
+ select
ts,
idle_percentage as value
- from cpu_idle_time_in_state_counters
- where state_name='${it.state_name}'`,
+ from cpu_idle_time_in_state_counters
+ where state_name = '${it.state_name}'
+ `,
group,
{unit: 'percent'},
);