xref: /aosp_15_r20/external/perfetto/src/trace_processor/containers/interval_intersector.h (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 #ifndef SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_INTERSECTOR_H_
18 #define SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_INTERSECTOR_H_
19 
20 #include <algorithm>
21 #include <cstddef>
22 #include <cstdint>
23 #include <limits>
24 #include <memory>
25 #include <utility>
26 #include <vector>
27 
28 #include "perfetto/base/logging.h"
29 #include "src/trace_processor/containers/interval_tree.h"
30 
31 namespace perfetto::trace_processor {
32 
33 // Provides functionality for efficient intersection of a set of intervals with
34 // another interval. Operates in various modes: using interval tree, binary
35 // search of non overlapping intervals or linear scan if the intervals are
36 // overlapping but there is no need for interval tree.
37 class IntervalIntersector {
38  public:
39   // Mode of intersection. Choosing the mode strongly impacts the performance
40   // of intersector.
41   enum Mode {
42     // Use `IntervalTree` as an underlying implementation.. Would create an
43     // interval tree - with complexity of O(N) and memory complexity of O(N).
44     // Query cost is O(logN).
45     // NOTE: Only use if intevals are overlapping and tree would be queried
46     // multiple times.
47     kIntervalTree,
48     // If the intervals are non overlapping we can use simple binary search.
49     // There is no memory cost and algorithmic complexity of O(logN + M), where
50     // logN is the cost of binary search and M is the number of results.
51     // NOTE: Only use if intervals are non overlapping.
52     kBinarySearch,
53     // Slightly better then linear scan, we are looking for the first
54     // overlapping interval and then doing linear scan of the rest. NOTE: Only
55     // use if intervals are overlapping and there would be very few queries.
56     kLinearScan
57   };
58 
59   // Creates an interval tree from the vector of intervals if needed. Otherwise
60   // copies the vector of intervals.
IntervalIntersector(const std::vector<Interval> & sorted_intervals,Mode mode)61   explicit IntervalIntersector(const std::vector<Interval>& sorted_intervals,
62                                Mode mode)
63       : intervals_(sorted_intervals), mode_(mode) {
64     if (sorted_intervals.empty()) {
65       mode_ = kBinarySearch;
66       return;
67     }
68     if (mode_ == kIntervalTree) {
69       tree = std::make_unique<IntervalTree>(intervals_);
70     }
71   }
72 
73   // Modifies |res| to contain Interval::Id of all intervals that overlap
74   // interval (s, e).
75   template <typename T>
FindOverlaps(uint64_t s,uint64_t e,std::vector<T> & res)76   void FindOverlaps(uint64_t s, uint64_t e, std::vector<T>& res) const {
77     if (mode_ == kIntervalTree) {
78       tree->FindOverlaps(s, e, res);
79       return;
80     }
81 
82     // Find the first interval that ends after |s|.
83     auto overlap =
84         std::lower_bound(intervals_.begin(), intervals_.end(), s,
85                          [](const Interval& interval, uint64_t start) {
86                            return interval.end <= start;
87                          });
88 
89     if (mode_ == kBinarySearch) {
90       for (; overlap != intervals_.end() && overlap->start < e; ++overlap) {
91         UpdateResultVector(s, e, *overlap, res);
92       }
93       return;
94     }
95 
96     PERFETTO_CHECK(mode_ == kLinearScan);
97 
98     for (; overlap != intervals_.end() && overlap->start < e; ++overlap) {
99       if (overlap->end <= s) {
100         continue;
101       }
102       if (overlap->start > s) {
103         break;
104       }
105       UpdateResultVector(s, e, *overlap, res);
106     }
107 
108     for (; overlap != intervals_.end() && overlap->start < e; ++overlap) {
109       UpdateResultVector(s, e, *overlap, res);
110     }
111   }
112 
113   // Helper function to decide which intersector mode would be in given
114   // situations. Only use if the number of queries is known.
DecideMode(bool is_nonoverlapping,uint32_t queries_count)115   static Mode DecideMode(bool is_nonoverlapping, uint32_t queries_count) {
116     if (is_nonoverlapping) {
117       return kBinarySearch;
118     }
119     if (queries_count < 5) {
120       return kLinearScan;
121     }
122     return kIntervalTree;
123   }
124 
125  private:
UpdateResultVector(uint64_t s,uint64_t e,const Interval & overlap,std::vector<Interval> & res)126   void UpdateResultVector(uint64_t s,
127                           uint64_t e,
128                           const Interval& overlap,
129                           std::vector<Interval>& res) const {
130     Interval new_int;
131     new_int.start = std::max(s, overlap.start);
132     new_int.end = std::min(e, overlap.end);
133     new_int.id = overlap.id;
134     res.push_back(new_int);
135   }
136 
UpdateResultVector(uint64_t,uint64_t,const Interval & overlap,std::vector<Id> & res)137   void UpdateResultVector(uint64_t,
138                           uint64_t,
139                           const Interval& overlap,
140 
141                           std::vector<Id>& res) const {
142     res.push_back(overlap.id);
143   }
144   const std::vector<Interval>& intervals_;
145   Mode mode_;
146 
147   // If |use_interval_tree_|.
148   std::unique_ptr<IntervalTree> tree;
149 };
150 
151 }  // namespace perfetto::trace_processor
152 
153 #endif  // SRC_TRACE_PROCESSOR_CONTAINERS_INTERVAL_INTERSECTOR_H_
154