1 /*
2 * Copyright (C) 2022 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/proto/active_chrome_processes_tracker.h"
18
19 namespace perfetto {
20 namespace trace_processor {
21
AddActiveProcessMetadata(int64_t timestamp,UniquePid upid)22 void ActiveChromeProcessesTracker::AddActiveProcessMetadata(int64_t timestamp,
23 UniquePid upid) {
24 process_data_[upid].metadata_timestamps.insert(timestamp);
25 global_metadata_timestamps_.insert(timestamp);
26 }
27
28 std::vector<ProcessWithDataLoss>
GetProcessesWithDataLoss() const29 ActiveChromeProcessesTracker::GetProcessesWithDataLoss() const {
30 std::vector<ProcessWithDataLoss> processes_with_data_loss;
31 for (auto it = process_data_.GetIterator(); it; ++it) {
32 UniquePid upid = it.key();
33 const auto& process_data = it.value();
34 std::optional<int64_t> last_loss_moment;
35 std::optional<int64_t> next_no_loss_moment;
36 for (int64_t metadata_ts : process_data.metadata_timestamps) {
37 // Looks for a matching process descriptor in the [t - 0.2s, t + 0.2s]
38 // window. The window size is somewhat arbitrary, and can be changed in
39 // the future. It should be smaller than the incremental state reset
40 // interval, which is 5s for Chromium traces.
41 constexpr int64_t kMaxTimestampDiff = 200 * 1000 * 1000;
42 auto descriptor_it = process_data.descriptor_timestamps.lower_bound(
43 metadata_ts - kMaxTimestampDiff);
44 if (descriptor_it != process_data.descriptor_timestamps.end()) {
45 if (*descriptor_it > metadata_ts + kMaxTimestampDiff) {
46 // There's no matching descriptor, but there's a descriptor at some
47 // point in the future.
48 last_loss_moment = metadata_ts;
49 next_no_loss_moment = *descriptor_it;
50 }
51 } else {
52 // There's no matching descriptor, and there're no descriptors in the
53 // future.
54 last_loss_moment = metadata_ts;
55 auto global_metadata_it =
56 global_metadata_timestamps_.upper_bound(metadata_ts);
57 if (global_metadata_it != global_metadata_timestamps_.end()) {
58 // The process terminated before the next incremental state reset.
59 // So it has no data loss from the next reset until the end of the
60 // trace.
61 next_no_loss_moment = *global_metadata_it;
62 } else {
63 next_no_loss_moment = std::nullopt;
64 }
65 }
66 }
67 if (last_loss_moment) {
68 processes_with_data_loss.push_back({upid, next_no_loss_moment});
69 }
70 }
71 return processes_with_data_loss;
72 }
73
NotifyEndOfFile()74 void ActiveChromeProcessesTracker::NotifyEndOfFile() {
75 const auto processes = GetProcessesWithDataLoss();
76 for (const auto& p : processes) {
77 tables::ExpMissingChromeProcTable::Row row;
78 row.upid = p.upid;
79 row.reliable_from = p.reliable_from;
80 context_->storage->mutable_experimental_missing_chrome_processes_table()
81 ->Insert(row);
82 }
83 }
84
85 } // namespace trace_processor
86 } // namespace perfetto
87