1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_UKM_SINGULAR_UKM_ENTRY_H_
#define COMPONENTS_UKM_SINGULAR_UKM_ENTRY_H_
#include <memory>
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace ukm {
template <typename>
class SingularUkmEntry;
// Creates the SingularUkmInterface receiver.
void CreateSingularUkmInterface(
mojo::PendingReceiver<mojom::SingularUkmInterface> receiver);
// Singular UKM Entries are UKM Entries that can be 'recorded' multiple times
// but only the last one will be recorded by the UKM Service. While not
// currently supported, it is designed to support entries from multiple
// processes and still record the UkmEntry in the event that the remote process
// is exited. If the browser process crashes then all entries that haven't been
// saved to a log are lost.
//
// Notice: This currently only works within the browser process. Multi-process
// is not implemented and changes need to be added to the startup
// process of the desired process.
//
// Create a new UKM entry as so:
//
// std::unique_ptr<SingularUkmEntry<AdFrameLoad>> entry =
// SingularUkmEntry<AdFrameLoad>::Create(source_id);
//
// {
// SingularUkmEntry<AdFrameLoad>::EntryBuilder builder = entry->Builder();
// builder->SetCpuTime_PeakWindowedPercent(cpu_time_pwp1);
// builder->SetCpuTime_Total(total_cpu_time1);
// }
// {
// SingularUkmEntry<AdFrameLoad>::EntryBuilder builder = entry->Builder();
// builder->SetCpuTime_PeakWindowedPercent(cpu_time_pwp2);
// builder->SetCpuTime_Total(total_cpu_time2);
// }
//
// In the example above, only cpu_time_pwp2 and total_cpu_time2 will be recorded
// by the UKM service when `entry` is destroyed. Destructor of `builder` will
// update the `entry`.
//
// Note:
// - Use arrow operator on the builder to access the underlying UkmEntry. This
// will give access to UkmEntry's methods.
// - When a EntryBuilder is destroyed or goes out of scope, the corresponding
// UkmEntry is committed as the latest to be recorded.
// - A SingularUkmEntry and the EntryBuilders created from it must be used on
// the same sequence it was created.
// - The UkmEntry will not be recorded until the SingularUkmEntry is destroyed.
// - The SingularUkmEntry must outlive all EntryBuilder's created from it.
// - All desired metrics must be set by the EntryBuilder to be recorded.
//
// Wrapper class to associate an UkmEntry type with an interface and source id.
// Template UkmEntry is expected to have a base class of UkmEntryBuilderBase.
// See tools/metrics/ukm/ukm.xml for entry definitions.
template <typename UkmEntry>
class SingularUkmEntry {
public:
// Creates a new SingularUkmEntry.
static std::unique_ptr<SingularUkmEntry<UkmEntry>> Create(
SourceId source_id) {
mojo::PendingRemote<mojom::SingularUkmInterface> remote;
CreateSingularUkmInterface(remote.InitWithNewPipeAndPassReceiver());
return base::WrapUnique(
new SingularUkmEntry<UkmEntry>(source_id, std::move(remote)));
}
SingularUkmEntry(const SingularUkmEntry<UkmEntry>&) = delete;
SingularUkmEntry& operator=(const SingularUkmEntry<UkmEntry>&) = delete;
~SingularUkmEntry() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
// Provides an interface to build the UkmEntry. The built UkmEntry is
// submitted to the interface on destruction.
class EntryBuilder {
public:
EntryBuilder(const EntryBuilder&) = delete;
EntryBuilder& operator=(const EntryBuilder&) = delete;
~EntryBuilder() {
DCHECK_CALLED_ON_VALID_SEQUENCE(singular_ukm_entry_->sequence_checker_);
singular_ukm_entry_->interface_->Submit(entry_.TakeEntry());
}
// Provides a simple interface to interact with the underlying UkmEntry.
UkmEntry* operator->() { return &entry_; }
private:
friend class SingularUkmEntry<UkmEntry>;
EntryBuilder(SourceId source_id,
SingularUkmEntry<UkmEntry>& singular_ukm_entry)
: entry_(source_id), singular_ukm_entry_(&singular_ukm_entry) {}
// The current entry being built.
UkmEntry entry_;
// The SingularUkmEntry that created |this|. It provides the Mojo interface
// to submit completed UKMEntryies.
raw_ptr<SingularUkmEntry<UkmEntry>> singular_ukm_entry_;
};
// Creates an EntryBuilder. EntryBuilders are used to build an UkmEntry and
// submit it to the receiver.
EntryBuilder Builder() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return EntryBuilder(source_id_, *this);
}
private:
SingularUkmEntry(SourceId source_id,
mojo::PendingRemote<mojom::SingularUkmInterface> interface)
: source_id_(source_id), interface_(std::move(interface)) {
CHECK(interface_);
}
// The SourceId to be used by new entries.
SourceId source_id_;
mojo::Remote<mojom::SingularUkmInterface> interface_;
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace ukm
#endif // COMPONENTS_UKM_SINGULAR_UKM_ENTRY_H_
|