| /* |
| * Copyright (C) 2025 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. |
| */ |
| |
| #include "src/traced/probes/ftrace/predefined_tracepoints.h" |
| |
| #include <map> |
| #include <set> |
| |
| #include "src/traced/probes/ftrace/proto_translation_table.h" |
| #include "src/traced/probes/ftrace/tracefs.h" |
| |
| namespace perfetto::predefined_tracepoints { |
| namespace { |
| void AddEventGroup(const ProtoTranslationTable* table, |
| const std::string& group, |
| base::FlatSet<GroupAndName>* to) { |
| const std::vector<const Event*>* events = table->GetEventsByGroup(group); |
| if (!events) |
| return; |
| for (const Event* event : *events) { |
| to->insert(GroupAndName(group, event->name)); |
| } |
| } |
| |
| void PERFETTO_NO_INLINE InsertEvent(const char* group, |
| const char* name, |
| base::FlatSet<GroupAndName>* dst) { |
| dst->insert(GroupAndName(group, name)); |
| } |
| |
| base::FlatSet<GroupAndName> GenerateGfxTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "mdss", &events); |
| InsertEvent("mdss", "rotator_bw_ao_as_context", &events); |
| InsertEvent("mdss", "mdp_trace_counter", &events); |
| InsertEvent("mdss", "tracing_mark_write", &events); |
| InsertEvent("mdss", "mdp_cmd_wait_pingpong", &events); |
| InsertEvent("mdss", "mdp_cmd_kickoff", &events); |
| InsertEvent("mdss", "mdp_cmd_release_bw", &events); |
| InsertEvent("mdss", "mdp_cmd_readptr_done", &events); |
| InsertEvent("mdss", "mdp_cmd_pingpong_done", &events); |
| InsertEvent("mdss", "mdp_misr_crc", &events); |
| InsertEvent("mdss", "mdp_compare_bw", &events); |
| InsertEvent("mdss", "mdp_perf_update_bus", &events); |
| InsertEvent("mdss", "mdp_video_underrun_done", &events); |
| InsertEvent("mdss", "mdp_commit", &events); |
| InsertEvent("mdss", "mdp_mixer_update", &events); |
| InsertEvent("mdss", "mdp_perf_prefill_calc", &events); |
| InsertEvent("mdss", "mdp_perf_set_ot", &events); |
| InsertEvent("mdss", "mdp_perf_set_wm_levels", &events); |
| InsertEvent("mdss", "mdp_perf_set_panic_luts", &events); |
| InsertEvent("mdss", "mdp_perf_set_qos_luts", &events); |
| InsertEvent("mdss", "mdp_sspp_change", &events); |
| InsertEvent("mdss", "mdp_sspp_set", &events); |
| AddEventGroup(table, "mali", &events); |
| InsertEvent("mali", "tracing_mark_write", &events); |
| |
| AddEventGroup(table, "sde", &events); |
| InsertEvent("sde", "tracing_mark_write", &events); |
| InsertEvent("sde", "sde_perf_update_bus", &events); |
| InsertEvent("sde", "sde_perf_set_qos_luts", &events); |
| InsertEvent("sde", "sde_perf_set_ot", &events); |
| InsertEvent("sde", "sde_perf_set_danger_luts", &events); |
| InsertEvent("sde", "sde_perf_crtc_update", &events); |
| InsertEvent("sde", "sde_perf_calc_crtc", &events); |
| InsertEvent("sde", "sde_evtlog", &events); |
| InsertEvent("sde", "sde_encoder_underrun", &events); |
| InsertEvent("sde", "sde_cmd_release_bw", &events); |
| |
| AddEventGroup(table, "dpu", &events); |
| InsertEvent("dpu", "tracing_mark_write", &events); |
| InsertEvent("dpu", "disp_dpu_underrun", &events); |
| |
| AddEventGroup(table, "g2d", &events); |
| InsertEvent("g2d", "tracing_mark_write", &events); |
| InsertEvent("g2d", "g2d_perf_update_qos", &events); |
| |
| AddEventGroup(table, "panel", &events); |
| InsertEvent("panel", "panel_write_generic", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateIonTracePoints() { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("kmem", "ion_alloc_buffer_start", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateSchedTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| // Note: sched_wakeup intentionally removed (diverging from atrace), as it |
| // is high-volume, but mostly redundant when sched_waking is also enabled. |
| // The event can still be enabled explicitly when necessary. |
| InsertEvent("sched", "sched_switch", &events); |
| InsertEvent("sched", "sched_waking", &events); |
| InsertEvent("sched", "sched_blocked_reason", &events); |
| InsertEvent("sched", "sched_cpu_hotplug", &events); |
| InsertEvent("sched", "sched_pi_setprio", &events); |
| InsertEvent("sched", "sched_process_exit", &events); |
| AddEventGroup(table, "cgroup", &events); |
| InsertEvent("cgroup", "cgroup_transfer_tasks", &events); |
| InsertEvent("cgroup", "cgroup_setup_root", &events); |
| InsertEvent("cgroup", "cgroup_rmdir", &events); |
| InsertEvent("cgroup", "cgroup_rename", &events); |
| InsertEvent("cgroup", "cgroup_remount", &events); |
| InsertEvent("cgroup", "cgroup_release", &events); |
| InsertEvent("cgroup", "cgroup_mkdir", &events); |
| InsertEvent("cgroup", "cgroup_destroy_root", &events); |
| InsertEvent("cgroup", "cgroup_attach_task", &events); |
| InsertEvent("oom", "oom_score_adj_update", &events); |
| InsertEvent("task", "task_rename", &events); |
| InsertEvent("task", "task_newtask", &events); |
| |
| AddEventGroup(table, "systrace", &events); |
| InsertEvent("systrace", "0", &events); |
| |
| AddEventGroup(table, "scm", &events); |
| InsertEvent("scm", "scm_call_start", &events); |
| InsertEvent("scm", "scm_call_end", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateIrqTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "irq", &events); |
| InsertEvent("irq", "tasklet_hi_exit", &events); |
| InsertEvent("irq", "tasklet_hi_entry", &events); |
| InsertEvent("irq", "tasklet_exit", &events); |
| InsertEvent("irq", "tasklet_entry", &events); |
| InsertEvent("irq", "softirq_raise", &events); |
| InsertEvent("irq", "softirq_exit", &events); |
| InsertEvent("irq", "softirq_entry", &events); |
| InsertEvent("irq", "irq_handler_exit", &events); |
| InsertEvent("irq", "irq_handler_entry", &events); |
| AddEventGroup(table, "ipi", &events); |
| InsertEvent("ipi", "ipi_raise", &events); |
| InsertEvent("ipi", "ipi_exit", &events); |
| InsertEvent("ipi", "ipi_entry", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateIrqOffTracePoints() { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("preemptirq", "irq_enable", &events); |
| InsertEvent("preemptirq", "irq_disable", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GeneratePreemptoffTracePoints() { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("preemptirq", "preempt_enable", &events); |
| InsertEvent("preemptirq", "preempt_disable", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateI2cTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "i2c", &events); |
| InsertEvent("i2c", "i2c_read", &events); |
| InsertEvent("i2c", "i2c_write", &events); |
| InsertEvent("i2c", "i2c_result", &events); |
| InsertEvent("i2c", "i2c_reply", &events); |
| InsertEvent("i2c", "smbus_read", &events); |
| InsertEvent("i2c", "smbus_write", &events); |
| InsertEvent("i2c", "smbus_result", &events); |
| InsertEvent("i2c", "smbus_reply", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateFreqTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("power", "cpu_frequency", &events); |
| InsertEvent("power", "gpu_frequency", &events); |
| InsertEvent("power", "clock_set_rate", &events); |
| InsertEvent("power", "clock_disable", &events); |
| InsertEvent("power", "clock_enable", &events); |
| InsertEvent("clk", "clk_set_rate", &events); |
| InsertEvent("clk", "clk_disable", &events); |
| InsertEvent("clk", "clk_enable", &events); |
| InsertEvent("power", "cpu_frequency_limits", &events); |
| InsertEvent("power", "suspend_resume", &events); |
| InsertEvent("cpuhp", "cpuhp_enter", &events); |
| InsertEvent("cpuhp", "cpuhp_exit", &events); |
| InsertEvent("cpuhp", "cpuhp_pause", &events); |
| AddEventGroup(table, "msm_bus", &events); |
| InsertEvent("msm_bus", "bus_update_request_end", &events); |
| InsertEvent("msm_bus", "bus_update_request", &events); |
| InsertEvent("msm_bus", "bus_rules_matches", &events); |
| InsertEvent("msm_bus", "bus_max_votes", &events); |
| InsertEvent("msm_bus", "bus_client_status", &events); |
| InsertEvent("msm_bus", "bus_bke_params", &events); |
| InsertEvent("msm_bus", "bus_bimc_config_limiter", &events); |
| InsertEvent("msm_bus", "bus_avail_bw", &events); |
| InsertEvent("msm_bus", "bus_agg_bw", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateMembusTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "memory_bus", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateIdleTracePoints() { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("power", "cpu_idle", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateDiskTracePoints() { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("f2fs", "f2fs_sync_file_enter", &events); |
| InsertEvent("f2fs", "f2fs_sync_file_exit", &events); |
| InsertEvent("f2fs", "f2fs_write_begin", &events); |
| InsertEvent("f2fs", "f2fs_write_end", &events); |
| InsertEvent("f2fs", "f2fs_iostat", &events); |
| InsertEvent("f2fs", "f2fs_iostat_latency", &events); |
| InsertEvent("ext4", "ext4_da_write_begin", &events); |
| InsertEvent("ext4", "ext4_da_write_end", &events); |
| InsertEvent("ext4", "ext4_sync_file_enter", &events); |
| InsertEvent("ext4", "ext4_sync_file_exit", &events); |
| InsertEvent("block", "block_bio_queue", &events); |
| InsertEvent("block", "block_bio_complete", &events); |
| InsertEvent("ufs", "ufshcd_command", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateMmcTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "mmc", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateLoadTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "cpufreq_interactive", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateSyncTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| // linux kernel < 4.9 |
| AddEventGroup(table, "sync", &events); |
| InsertEvent("sync", "sync_pt", &events); |
| InsertEvent("sync", "sync_timeline", &events); |
| InsertEvent("sync", "sync_wait", &events); |
| // linux kernel == 4.9.x |
| AddEventGroup(table, "fence", &events); |
| InsertEvent("fence", "fence_annotate_wait_on", &events); |
| InsertEvent("fence", "fence_destroy", &events); |
| InsertEvent("fence", "fence_emit", &events); |
| InsertEvent("fence", "fence_enable_signal", &events); |
| InsertEvent("fence", "fence_init", &events); |
| InsertEvent("fence", "fence_signaled", &events); |
| InsertEvent("fence", "fence_wait_end", &events); |
| InsertEvent("fence", "fence_wait_start", &events); |
| // linux kernel > 4.9 |
| AddEventGroup(table, "dma_fence", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateWorkqTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "workqueue", &events); |
| InsertEvent("workqueue", "workqueue_queue_work", &events); |
| InsertEvent("workqueue", "workqueue_execute_start", &events); |
| InsertEvent("workqueue", "workqueue_execute_end", &events); |
| InsertEvent("workqueue", "workqueue_activate_work", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateMemreclaimTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("vmscan", "mm_vmscan_direct_reclaim_begin", &events); |
| InsertEvent("vmscan", "mm_vmscan_direct_reclaim_end", &events); |
| InsertEvent("vmscan", "mm_vmscan_kswapd_wake", &events); |
| InsertEvent("vmscan", "mm_vmscan_kswapd_sleep", &events); |
| AddEventGroup(table, "lowmemorykiller", &events); |
| InsertEvent("lowmemorykiller", "lowmemory_kill", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateRegulatorsTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "regulator", &events); |
| InsertEvent("regulator", "regulator_set_voltage_complete", &events); |
| InsertEvent("regulator", "regulator_set_voltage", &events); |
| InsertEvent("regulator", "regulator_enable_delay", &events); |
| InsertEvent("regulator", "regulator_enable_complete", &events); |
| InsertEvent("regulator", "regulator_enable", &events); |
| InsertEvent("regulator", "regulator_disable_complete", &events); |
| InsertEvent("regulator", "regulator_disable", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateBinderDriverTracePoints() { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("binder", "binder_transaction", &events); |
| InsertEvent("binder", "binder_transaction_received", &events); |
| InsertEvent("binder", "binder_transaction_alloc_buf", &events); |
| InsertEvent("binder", "binder_set_priority", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateBinderLockTracePoints() { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("binder", "binder_lock", &events); |
| InsertEvent("binder", "binder_locked", &events); |
| InsertEvent("binder", "binder_unlock", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GeneratePagecacheTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "filemap", &events); |
| InsertEvent("filemap", "mm_filemap_delete_from_page_cache", &events); |
| InsertEvent("filemap", "mm_filemap_add_to_page_cache", &events); |
| InsertEvent("filemap", "filemap_set_wb_err", &events); |
| InsertEvent("filemap", "file_check_and_advance_wb_err", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateMemoryTracePoints(Tracefs* ftrace) { |
| base::FlatSet<GroupAndName> events; |
| // Use rss_stat_throttled if supported |
| if (ftrace->SupportsRssStatThrottled()) { |
| InsertEvent("synthetic", "rss_stat_throttled", &events); |
| } else { |
| InsertEvent("kmem", "rss_stat", &events); |
| } |
| InsertEvent("kmem", "ion_heap_grow", &events); |
| InsertEvent("kmem", "ion_heap_shrink", &events); |
| // ion_stat supersedes ion_heap_grow / shrink for kernel 4.19+ |
| InsertEvent("ion", "ion_stat", &events); |
| InsertEvent("mm_event", "mm_event_record", &events); |
| InsertEvent("dmabuf_heap", "dma_heap_stat", &events); |
| InsertEvent("gpu_mem", "gpu_mem_total", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateThermalTracePoints() { |
| base::FlatSet<GroupAndName> events; |
| InsertEvent("thermal", "thermal_temperature", &events); |
| InsertEvent("thermal", "cdev_update", &events); |
| return events; |
| } |
| |
| base::FlatSet<GroupAndName> GenerateCameraTracePoints( |
| const ProtoTranslationTable* table) { |
| base::FlatSet<GroupAndName> events; |
| AddEventGroup(table, "lwis", &events); |
| InsertEvent("lwis", "tracing_mark_write", &events); |
| return events; |
| } |
| |
| std::map<std::string, base::FlatSet<GroupAndName>> |
| GeneratePredefinedTracePoints(const ProtoTranslationTable* table, |
| Tracefs* ftrace) { |
| // Ideally we should keep this code in sync with: |
| // platform/frameworks/native/cmds/atrace/atrace.cpp |
| // It's not a disaster if they go out of sync, we can always add the ftrace |
| // categories manually server side but this is user friendly and reduces the |
| // size of the configs. |
| std::map<std::string, base::FlatSet<GroupAndName>> tracepoints; |
| |
| tracepoints["gfx"] = GenerateGfxTracePoints(table); |
| tracepoints["ion"] = GenerateIonTracePoints(); |
| tracepoints["sched"] = GenerateSchedTracePoints(table); |
| tracepoints["irq"] = GenerateIrqTracePoints(table); |
| tracepoints["irqoff"] = GenerateIrqOffTracePoints(); |
| tracepoints["preemptoff"] = GeneratePreemptoffTracePoints(); |
| tracepoints["i2c"] = GenerateI2cTracePoints(table); |
| tracepoints["freq"] = GenerateFreqTracePoints(table); |
| tracepoints["membus"] = GenerateMembusTracePoints(table); |
| tracepoints["idle"] = GenerateIdleTracePoints(); |
| tracepoints["disk"] = GenerateDiskTracePoints(); |
| tracepoints["mmc"] = GenerateMmcTracePoints(table); |
| tracepoints["load"] = GenerateLoadTracePoints(table); |
| tracepoints["sync"] = GenerateSyncTracePoints(table); |
| tracepoints["workq"] = GenerateWorkqTracePoints(table); |
| tracepoints["memreclaim"] = GenerateMemreclaimTracePoints(table); |
| tracepoints["regulators"] = GenerateRegulatorsTracePoints(table); |
| tracepoints["binder_driver"] = GenerateBinderDriverTracePoints(); |
| tracepoints["binder_lock"] = GenerateBinderLockTracePoints(); |
| tracepoints["pagecache"] = GeneratePagecacheTracePoints(table); |
| tracepoints["memory"] = GenerateMemoryTracePoints(ftrace); |
| tracepoints["thermal"] = GenerateThermalTracePoints(); |
| tracepoints["camera"] = GenerateCameraTracePoints(table); |
| return tracepoints; |
| } |
| } // namespace |
| |
| std::map<std::string, base::FlatSet<GroupAndName>> GetPredefinedTracePoints( |
| const ProtoTranslationTable* table, |
| Tracefs* ftrace) { |
| return GeneratePredefinedTracePoints(table, ftrace); |
| } |
| |
| std::map<std::string, base::FlatSet<GroupAndName>> |
| GetAccessiblePredefinedTracePoints(const ProtoTranslationTable* table, |
| Tracefs* ftrace) { |
| auto tracepoints = GetPredefinedTracePoints(table, ftrace); |
| |
| bool generic_enable = ftrace->IsGenericSetEventWritable(); |
| |
| std::map<std::string, base::FlatSet<GroupAndName>> accessible_tracepoints; |
| for (const auto& [category, events] : tracepoints) { |
| base::FlatSet<GroupAndName> accessible_events; |
| for (const auto& event : events) { |
| if (generic_enable |
| ? ftrace->IsEventFormatReadable(event.group(), event.name()) |
| : ftrace->IsEventAccessible(event.group(), event.name())) { |
| accessible_events.insert(event); |
| } |
| } |
| if (!accessible_events.empty()) { |
| accessible_tracepoints[category] = accessible_events; |
| } |
| } |
| return accessible_tracepoints; |
| } |
| } // namespace perfetto::predefined_tracepoints |