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