Coverage Report

Created: 2025-12-31 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/perfetto/include/perfetto/base/flat_set.h
Line
Count
Source
1
/*
2
 * Copyright (C) 2019 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 INCLUDE_PERFETTO_BASE_FLAT_SET_H_
18
#define INCLUDE_PERFETTO_BASE_FLAT_SET_H_
19
20
#include <stddef.h>
21
22
#include <algorithm>
23
#include <utility>
24
#include <vector>
25
26
// A vector-based set::set-like container.
27
// It's more cache friendly than std::*set and performs for cases where:
28
// 1. A high number of dupes is expected (e.g. pid tracking in ftrace).
29
// 2. The working set is small (hundreds of elements).
30
31
// Performance characteristics (for uniformly random insertion order):
32
// - For smaller insertions (up to ~500), it outperforms both std::set<int> and
33
//   std::unordered_set<int> by ~3x.
34
// - Up until 4k insertions, it is always faster than std::set<int>.
35
// - unordered_set<int> is faster with more than 2k insertions.
36
// - unordered_set, however, it's less memory efficient and has more caveats
37
//   (see chromium's base/containers/README.md).
38
//
39
// See flat_set_benchmark.cc and the charts in go/perfetto-int-set-benchmark.
40
41
namespace perfetto {
42
namespace base {
43
44
template <typename T>
45
class FlatSet {
46
 public:
47
  using value_type = T;
48
  using const_pointer = const T*;
49
  using iterator = typename std::vector<T>::iterator;
50
  using const_iterator = typename std::vector<T>::const_iterator;
51
52
9.22k
  FlatSet() = default;
perfetto::base::FlatSet<std::__1::pair<unsigned long, unsigned long> >::FlatSet()
Line
Count
Source
52
1.31k
  FlatSet() = default;
perfetto::base::FlatSet<int>::FlatSet()
Line
Count
Source
52
2.63k
  FlatSet() = default;
perfetto::base::FlatSet<perfetto::FtraceMetadata::KernelAddr>::FlatSet()
Line
Count
Source
52
1.31k
  FlatSet() = default;
perfetto::base::FlatSet<std::__1::pair<int, unsigned long> >::FlatSet()
Line
Count
Source
52
1.31k
  FlatSet() = default;
perfetto::base::FlatSet<long>::FlatSet()
Line
Count
Source
52
1.31k
  FlatSet() = default;
perfetto::base::FlatSet<perfetto::protos::pbzero::FtraceParseStatus>::FlatSet()
Line
Count
Source
52
1.31k
  FlatSet() = default;
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::GroupAndName>::FlatSet()
perfetto::base::FlatSet<perfetto::PrintkEntry>::FlatSet()
Line
Count
Source
52
1
  FlatSet() = default;
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::ProcessStatsDataSource::SeenPid>::FlatSet()
Unexecuted instantiation: perfetto::base::FlatSet<unsigned long>::FlatSet()
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::trace_processor::tables::StackProfileCallsiteTable::Id>::FlatSet()
53
54
  // Mainly for tests. Deliberately not marked as "explicit".
55
  FlatSet(std::initializer_list<T> initial) : entries_(initial) {
56
    std::sort(entries_.begin(), entries_.end());
57
    entries_.erase(std::unique(entries_.begin(), entries_.end()),
58
                   entries_.end());
59
  }
60
61
0
  const_iterator find(T value) const {
62
0
    auto entries_end = entries_.end();
63
0
    auto it = std::lower_bound(entries_.begin(), entries_end, value);
64
0
    return (it != entries_end && *it == value) ? it : entries_end;
65
0
  }
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::PrintkEntry>::find(perfetto::PrintkEntry) const
Unexecuted instantiation: perfetto::base::FlatSet<long>::find(long) const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::ProcessStatsDataSource::SeenPid>::find(perfetto::ProcessStatsDataSource::SeenPid) const
Unexecuted instantiation: perfetto::base::FlatSet<unsigned long>::find(unsigned long) const
66
67
0
  size_t count(T value) const { return find(value) == entries_.end() ? 0 : 1; }
Unexecuted instantiation: perfetto::base::FlatSet<long>::count(long) const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::ProcessStatsDataSource::SeenPid>::count(perfetto::ProcessStatsDataSource::SeenPid) const
Unexecuted instantiation: perfetto::base::FlatSet<unsigned long>::count(unsigned long) const
68
69
12.5k
  std::pair<iterator, bool> insert(T value) {
70
12.5k
    auto entries_end = entries_.end();
71
12.5k
    auto it = std::lower_bound(entries_.begin(), entries_end, value);
72
12.5k
    if (it != entries_end && *it == value)
73
5.44k
      return std::make_pair(it, false);
74
    // If the value is not found |it| is either end() or the next item strictly
75
    // greater than |value|. In both cases we want to insert just before that.
76
7.14k
    it = entries_.insert(it, std::move(value));
77
7.14k
    return std::make_pair(it, true);
78
12.5k
  }
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<unsigned long, unsigned long> >::insert(std::__1::pair<unsigned long, unsigned long>)
perfetto::base::FlatSet<int>::insert(int)
Line
Count
Source
69
11.4k
  std::pair<iterator, bool> insert(T value) {
70
11.4k
    auto entries_end = entries_.end();
71
11.4k
    auto it = std::lower_bound(entries_.begin(), entries_end, value);
72
11.4k
    if (it != entries_end && *it == value)
73
5.44k
      return std::make_pair(it, false);
74
    // If the value is not found |it| is either end() or the next item strictly
75
    // greater than |value|. In both cases we want to insert just before that.
76
6.00k
    it = entries_.insert(it, std::move(value));
77
6.00k
    return std::make_pair(it, true);
78
11.4k
  }
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::FtraceMetadata::KernelAddr>::insert(perfetto::FtraceMetadata::KernelAddr)
perfetto::base::FlatSet<perfetto::PrintkEntry>::insert(perfetto::PrintkEntry)
Line
Count
Source
69
5
  std::pair<iterator, bool> insert(T value) {
70
5
    auto entries_end = entries_.end();
71
5
    auto it = std::lower_bound(entries_.begin(), entries_end, value);
72
5
    if (it != entries_end && *it == value)
73
1
      return std::make_pair(it, false);
74
    // If the value is not found |it| is either end() or the next item strictly
75
    // greater than |value|. In both cases we want to insert just before that.
76
4
    it = entries_.insert(it, std::move(value));
77
4
    return std::make_pair(it, true);
78
5
  }
perfetto::base::FlatSet<perfetto::protos::pbzero::FtraceParseStatus>::insert(perfetto::protos::pbzero::FtraceParseStatus)
Line
Count
Source
69
1.13k
  std::pair<iterator, bool> insert(T value) {
70
1.13k
    auto entries_end = entries_.end();
71
1.13k
    auto it = std::lower_bound(entries_.begin(), entries_end, value);
72
1.13k
    if (it != entries_end && *it == value)
73
0
      return std::make_pair(it, false);
74
    // If the value is not found |it| is either end() or the next item strictly
75
    // greater than |value|. In both cases we want to insert just before that.
76
1.13k
    it = entries_.insert(it, std::move(value));
77
1.13k
    return std::make_pair(it, true);
78
1.13k
  }
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<int, unsigned long> >::insert(std::__1::pair<int, unsigned long>)
Unexecuted instantiation: perfetto::base::FlatSet<long>::insert(long)
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::GroupAndName>::insert(perfetto::GroupAndName)
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::ProcessStatsDataSource::SeenPid>::insert(perfetto::ProcessStatsDataSource::SeenPid)
Unexecuted instantiation: perfetto::base::FlatSet<unsigned long>::insert(unsigned long)
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::trace_processor::tables::StackProfileCallsiteTable::Id>::insert(perfetto::trace_processor::tables::StackProfileCallsiteTable::Id)
79
80
0
  size_t erase(T value) {
81
0
    auto it = find(value);
82
0
    if (it == entries_.end())
83
0
      return 0;
84
0
    entries_.erase(it);
85
0
    return 1;
86
0
  }
87
88
0
  void clear() { entries_.clear(); }
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<unsigned long, unsigned long> >::clear()
Unexecuted instantiation: perfetto::base::FlatSet<int>::clear()
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::FtraceMetadata::KernelAddr>::clear()
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<int, unsigned long> >::clear()
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::GroupAndName>::clear()
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::ProcessStatsDataSource::SeenPid>::clear()
89
90
0
  bool empty() const { return entries_.empty(); }
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::PrintkEntry>::empty() const
Unexecuted instantiation: perfetto::base::FlatSet<int>::empty() const
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<int, unsigned long> >::empty() const
91
3.95k
  void reserve(size_t n) { entries_.reserve(n); }
perfetto::base::FlatSet<int>::reserve(unsigned long)
Line
Count
Source
91
2.63k
  void reserve(size_t n) { entries_.reserve(n); }
perfetto::base::FlatSet<perfetto::FtraceMetadata::KernelAddr>::reserve(unsigned long)
Line
Count
Source
91
1.31k
  void reserve(size_t n) { entries_.reserve(n); }
92
0
  size_t size() const { return entries_.size(); }
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::FtraceMetadata::KernelAddr>::size() const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::PrintkEntry>::size() const
93
0
  const_iterator begin() const { return entries_.begin(); }
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::FtraceMetadata::KernelAddr>::begin() const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::GroupAndName>::begin() const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::protos::pbzero::FtraceParseStatus>::begin() const
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<unsigned long, unsigned long> >::begin() const
Unexecuted instantiation: perfetto::base::FlatSet<int>::begin() const
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<int, unsigned long> >::begin() const
94
0
  const_iterator end() const { return entries_.end(); }
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::PrintkEntry>::end() const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::FtraceMetadata::KernelAddr>::end() const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::GroupAndName>::end() const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::protos::pbzero::FtraceParseStatus>::end() const
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<unsigned long, unsigned long> >::end() const
Unexecuted instantiation: perfetto::base::FlatSet<int>::end() const
Unexecuted instantiation: perfetto::base::FlatSet<std::__1::pair<int, unsigned long> >::end() const
Unexecuted instantiation: perfetto::base::FlatSet<perfetto::ProcessStatsDataSource::SeenPid>::end() const
95
96
 private:
97
  std::vector<T> entries_;
98
};
99
100
}  // namespace base
101
}  // namespace perfetto
102
103
#endif  // INCLUDE_PERFETTO_BASE_FLAT_SET_H_