xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/common/legacy_v8_cpu_profile_tracker.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 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 
17 #include "src/trace_processor/importers/common/legacy_v8_cpu_profile_tracker.h"
18 
19 #include <cstdint>
20 #include <optional>
21 #include <utility>
22 
23 #include "perfetto/base/status.h"
24 #include "perfetto/ext/base/flat_hash_map.h"
25 #include "perfetto/ext/base/status_or.h"
26 #include "perfetto/ext/base/string_view.h"
27 #include "src/trace_processor/importers/common/mapping_tracker.h"
28 #include "src/trace_processor/importers/common/process_tracker.h"
29 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
30 #include "src/trace_processor/storage/trace_storage.h"
31 #include "src/trace_processor/tables/profiler_tables_py.h"
32 #include "src/trace_processor/types/trace_processor_context.h"
33 
34 namespace perfetto::trace_processor {
35 
LegacyV8CpuProfileTracker(TraceProcessorContext * context)36 LegacyV8CpuProfileTracker::LegacyV8CpuProfileTracker(
37     TraceProcessorContext* context)
38     : context_(context) {}
39 
SetStartTsForSessionAndPid(uint64_t session_id,uint32_t pid,int64_t ts)40 void LegacyV8CpuProfileTracker::SetStartTsForSessionAndPid(uint64_t session_id,
41                                                            uint32_t pid,
42                                                            int64_t ts) {
43   auto [it, inserted] = state_by_session_and_pid_.Insert(
44       std::make_pair(session_id, pid),
45       State{ts, base::FlatHashMap<uint32_t, CallsiteId>(), nullptr});
46   it->ts = ts;
47   if (inserted) {
48     it->mapping = &context_->mapping_tracker->CreateDummyMapping("");
49   }
50 }
51 
AddCallsite(uint64_t session_id,uint32_t pid,uint32_t raw_callsite_id,std::optional<uint32_t> parent_raw_callsite_id,base::StringView script_url,base::StringView function_name)52 base::Status LegacyV8CpuProfileTracker::AddCallsite(
53     uint64_t session_id,
54     uint32_t pid,
55     uint32_t raw_callsite_id,
56     std::optional<uint32_t> parent_raw_callsite_id,
57     base::StringView script_url,
58     base::StringView function_name) {
59   auto* state = state_by_session_and_pid_.Find(std::make_pair(session_id, pid));
60   if (!state) {
61     return base::ErrStatus(
62         "v8 profile id does not exist: cannot insert callsite");
63   }
64   FrameId frame_id =
65       state->mapping->InternDummyFrame(function_name, script_url);
66   CallsiteId callsite_id;
67   if (parent_raw_callsite_id) {
68     auto* parent_id = state->callsites.Find(*parent_raw_callsite_id);
69     if (!parent_id) {
70       return base::ErrStatus(
71           "v8 profile parent id does not exist: cannot insert callsite");
72     }
73     auto row =
74         context_->storage->stack_profile_callsite_table().FindById(*parent_id);
75     callsite_id = context_->stack_profile_tracker->InternCallsite(
76         *parent_id, frame_id, row->depth() + 1);
77   } else {
78     callsite_id = context_->stack_profile_tracker->InternCallsite(std::nullopt,
79                                                                   frame_id, 0);
80   }
81   if (!state->callsites.Insert(raw_callsite_id, callsite_id).second) {
82     return base::ErrStatus("v8 profile: callsite with id already exists");
83   }
84   return base::OkStatus();
85 }
86 
AddDeltaAndGetTs(uint64_t session_id,uint32_t pid,int64_t delta_ts)87 base::StatusOr<int64_t> LegacyV8CpuProfileTracker::AddDeltaAndGetTs(
88     uint64_t session_id,
89     uint32_t pid,
90     int64_t delta_ts) {
91   auto* state = state_by_session_and_pid_.Find(std::make_pair(session_id, pid));
92   if (!state) {
93     return base::ErrStatus(
94         "v8 profile id does not exist: cannot compute timestamp from delta");
95   }
96   state->ts += delta_ts;
97   return state->ts;
98 }
99 
AddSample(int64_t ts,uint64_t session_id,uint32_t pid,uint32_t tid,uint32_t raw_callsite_id)100 base::Status LegacyV8CpuProfileTracker::AddSample(int64_t ts,
101                                                   uint64_t session_id,
102                                                   uint32_t pid,
103                                                   uint32_t tid,
104                                                   uint32_t raw_callsite_id) {
105   auto* state = state_by_session_and_pid_.Find(std::make_pair(session_id, pid));
106   if (!state) {
107     return base::ErrStatus("v8 callsite id does not exist: cannot add sample");
108   }
109   auto* id = state->callsites.Find(raw_callsite_id);
110   if (!id) {
111     return base::ErrStatus("v8 callsite id does not exist: cannot add sample");
112   }
113   UniqueTid utid = context_->process_tracker->UpdateThread(tid, pid);
114   auto* samples = context_->storage->mutable_cpu_profile_stack_sample_table();
115   samples->Insert({ts, *id, utid, 0});
116   return base::OkStatus();
117 }
118 
119 }  // namespace perfetto::trace_processor
120