Allow chrome://histograms selecting histogram while monitoring
In crbug.com/40864008 it was discussed that selecting histogram while in monitoring mode isn't really supported because as soon as new data comes the selection gets invalidated. The only way to monitor single histogram as to select them before getting into monitoring mode. This attempts to fix that by doing the following: 1. Make `StartMonitoring` ignore the query taking the baseline of ALL the histograms even if one is preselected. This is done to allow selection change without changing a base point. 2. Make `GetDiff` not ignore the query returning only the histogram that is actually requested by a frontend page. 3. Don't force `requestHistograms` when hash selection changes during monitoring mode. This mixes monitoring data which are diff from baseline with a global histogram data. With monitoring mode the updated data will be pulled with the next fetch anyway (within 1s). 4. Link header to `#` allowing to reset selection (aka. `query`) without refreshing the whole page and therefore the baseline. This allows changing selection live and opens potential for selecting multiple histograms. There is a small risk of increased memory footprint for users doing a lot of selective monitoring as each of them will now keep the whole "baseline" set of histograms. However it seems like an extremely obscure use case and the footprint is not enormous anyway O(kB). Tested: * Updated and added new coverage to automated testing * Checked the functionality with local build on gLinux Change-Id: I8fbf6e7fc138e2639e2d5ea5dff2d48a5666075a Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6175086 Reviewed-by: John Lee <johntlee@chromium.org> Commit-Queue: Andrzej Fiedukowicz <afie@google.com> Reviewed-by: Alexei Svitkine <asvitkine@chromium.org> Cr-Commit-Position: refs/heads/main@{#1409115}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
e848f2efd2
commit
f5d01b5969
content/browser
@ -136,7 +136,7 @@ void HistogramsMessageHandler::HandleStartMoninoring(
|
||||
const base::Value::List& args) {
|
||||
JsParams params = AllowJavascriptAndUnpackParams(args);
|
||||
ImportHistograms(params.include_subprocesses);
|
||||
histogram_monitor_.StartMonitoring(params.query);
|
||||
histogram_monitor_.StartMonitoring();
|
||||
ResolveJavascriptCallback(base::Value(params.callback_id),
|
||||
base::Value("Success"));
|
||||
}
|
||||
@ -144,7 +144,7 @@ void HistogramsMessageHandler::HandleStartMoninoring(
|
||||
void HistogramsMessageHandler::HandleFetchDiff(const base::Value::List& args) {
|
||||
JsParams params = AllowJavascriptAndUnpackParams(args);
|
||||
ImportHistograms(params.include_subprocesses);
|
||||
base::Value::List histograms_list = histogram_monitor_.GetDiff();
|
||||
base::Value::List histograms_list = histogram_monitor_.GetDiff(params.query);
|
||||
ResolveJavascriptCallback(base::Value(params.callback_id),
|
||||
std::move(histograms_list));
|
||||
}
|
||||
|
@ -13,22 +13,19 @@ HistogramsMonitor::HistogramsMonitor() = default;
|
||||
|
||||
HistogramsMonitor::~HistogramsMonitor() = default;
|
||||
|
||||
void HistogramsMonitor::StartMonitoring(std::string_view query) {
|
||||
query_ = query;
|
||||
void HistogramsMonitor::StartMonitoring() {
|
||||
histograms_snapshot_.clear();
|
||||
// Save a snapshot of all current histograms that will be used as a baseline.
|
||||
for (const auto* const histogram : base::StatisticsRecorder::WithName(
|
||||
base::StatisticsRecorder::GetHistograms(), query_,
|
||||
/*case_sensitive=*/false)) {
|
||||
for (const auto* histogram : base::StatisticsRecorder::GetHistograms()) {
|
||||
histograms_snapshot_[histogram->histogram_name()] =
|
||||
histogram->SnapshotSamples();
|
||||
}
|
||||
}
|
||||
|
||||
base::Value::List HistogramsMonitor::GetDiff() {
|
||||
base::Value::List HistogramsMonitor::GetDiff(const std::string& query) {
|
||||
base::StatisticsRecorder::Histograms histograms =
|
||||
base::StatisticsRecorder::Sort(base::StatisticsRecorder::WithName(
|
||||
base::StatisticsRecorder::GetHistograms(), query_,
|
||||
base::StatisticsRecorder::GetHistograms(), query,
|
||||
/*case_sensitive=*/false));
|
||||
return GetDiffInternal(histograms);
|
||||
}
|
||||
|
@ -32,11 +32,12 @@ class CONTENT_EXPORT HistogramsMonitor {
|
||||
|
||||
// Fetches and records a snapshot of the current histograms, as the baseline
|
||||
// to compare against in subsequent calls to GetDiff().
|
||||
void StartMonitoring(std::string_view query);
|
||||
void StartMonitoring();
|
||||
|
||||
// Gets the histogram diffs between the current histograms and the snapshot
|
||||
// recorded in StartMonitoring().
|
||||
base::Value::List GetDiff();
|
||||
// recorded in StartMonitoring(). Only returns the histograms that match
|
||||
// the query string.
|
||||
base::Value::List GetDiff(const std::string& query);
|
||||
|
||||
private:
|
||||
// Gets the difference between the histograms argument and the stored snapshot
|
||||
@ -44,7 +45,6 @@ class CONTENT_EXPORT HistogramsMonitor {
|
||||
base::Value::List GetDiffInternal(
|
||||
const base::StatisticsRecorder::Histograms& histograms);
|
||||
|
||||
std::string query_;
|
||||
std::map<std::string, std::unique_ptr<base::HistogramSamples>>
|
||||
histograms_snapshot_;
|
||||
};
|
||||
|
@ -12,6 +12,12 @@
|
||||
|
||||
namespace content {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::string kEmptyFilter = "";
|
||||
|
||||
} // namespace
|
||||
|
||||
class HistogramsMonitorTest : public testing::Test {
|
||||
public:
|
||||
HistogramsMonitorTest()
|
||||
@ -26,17 +32,17 @@ TEST_F(HistogramsMonitorTest, StartMonitoringThenGetDiff) {
|
||||
"MonitorHistogram1", 1, 1000, 10, base::HistogramBase::kNoFlags);
|
||||
histogram1->Add(30);
|
||||
HistogramsMonitor monitor;
|
||||
monitor.StartMonitoring(/*query=*/"");
|
||||
monitor.StartMonitoring();
|
||||
|
||||
// Get diff immediately should return nothing.
|
||||
base::Value::List diff = monitor.GetDiff();
|
||||
base::Value::List diff = monitor.GetDiff(kEmptyFilter);
|
||||
ASSERT_EQ(diff.size(), 0ull);
|
||||
|
||||
// Add more data to histogram.
|
||||
histogram1->Add(30);
|
||||
histogram1->Add(40);
|
||||
|
||||
diff = monitor.GetDiff();
|
||||
diff = monitor.GetDiff(kEmptyFilter);
|
||||
ASSERT_EQ(diff.size(), 1ull);
|
||||
std::string* header1 = diff[0].GetDict().FindString("header");
|
||||
EXPECT_EQ(*header1,
|
||||
@ -46,7 +52,7 @@ TEST_F(HistogramsMonitorTest, StartMonitoringThenGetDiff) {
|
||||
base::HistogramBase* histogram2 = base::Histogram::FactoryGet(
|
||||
"MonitorHistogram2", 1, 1000, 10, base::HistogramBase::kNoFlags);
|
||||
histogram2->Add(50);
|
||||
diff = monitor.GetDiff();
|
||||
diff = monitor.GetDiff(kEmptyFilter);
|
||||
ASSERT_EQ(diff.size(), 2ull);
|
||||
std::string* header2 = diff[1].GetDict().FindString("header");
|
||||
EXPECT_EQ(*header2,
|
||||
@ -60,12 +66,12 @@ TEST_F(HistogramsMonitorTest, StartMonitoringWithQueryThenGetDiff) {
|
||||
"MonitorHistogram1", 1, 1000, 10, base::HistogramBase::kNoFlags);
|
||||
histogram1->Add(30);
|
||||
HistogramsMonitor monitor;
|
||||
monitor.StartMonitoring(/*query=*/"MonitorHistogram1");
|
||||
monitor.StartMonitoring();
|
||||
|
||||
base::HistogramBase* histogram2 = base::Histogram::FactoryGet(
|
||||
"MonitorHistogram2", 1, 1000, 10, base::HistogramBase::kNoFlags);
|
||||
histogram2->Add(50);
|
||||
base::Value::List diff = monitor.GetDiff();
|
||||
base::Value::List diff = monitor.GetDiff("MonitorHistogram1");
|
||||
ASSERT_EQ(diff.size(), 0ull);
|
||||
}
|
||||
|
||||
@ -78,24 +84,83 @@ TEST_F(HistogramsMonitorTest, CaseInsensitiveQuery) {
|
||||
histogram1->Add(30);
|
||||
|
||||
HistogramsMonitor monitor;
|
||||
monitor.StartMonitoring(/*query=*/"histogram1");
|
||||
monitor.StartMonitoring();
|
||||
|
||||
base::HistogramBase* histogram2 = base::Histogram::FactoryGet(
|
||||
"MonitorHistogram2", 1, 1000, 10, base::HistogramBase::kNoFlags);
|
||||
histogram2->Add(50);
|
||||
|
||||
// The query shouldn't match "MonitorHistogram2".
|
||||
base::Value::List diff = monitor.GetDiff();
|
||||
base::Value::List diff = monitor.GetDiff("histogram1");
|
||||
ASSERT_EQ(diff.size(), 0ull);
|
||||
|
||||
histogram1->Add(10);
|
||||
|
||||
// The query should match "MonitorHistogram1", since it's case insensitive.
|
||||
diff = monitor.GetDiff();
|
||||
diff = monitor.GetDiff("histogram1");
|
||||
ASSERT_EQ(diff.size(), 1ull);
|
||||
std::string* header2 = diff[0].GetDict().FindString("header");
|
||||
EXPECT_EQ(*header2,
|
||||
"Histogram: MonitorHistogram1 recorded 1 samples, mean = 10.0");
|
||||
}
|
||||
|
||||
TEST_F(HistogramsMonitorTest, MonitoringBaselineDoesntChangeWithFilter) {
|
||||
base::StatisticsRecorder::ForgetHistogramForTesting("MonitorHistogram1");
|
||||
base::StatisticsRecorder::ForgetHistogramForTesting("MonitorHistogram2");
|
||||
base::HistogramBase* histogram1 = base::Histogram::FactoryGet(
|
||||
"MonitorHistogram1", 1, 1000, 10, base::HistogramBase::kNoFlags);
|
||||
histogram1->Add(30);
|
||||
|
||||
base::HistogramBase* histogram2 = base::Histogram::FactoryGet(
|
||||
"MonitorHistogram2", 1, 1000, 10, base::HistogramBase::kNoFlags);
|
||||
histogram2->Add(50);
|
||||
HistogramsMonitor monitor;
|
||||
|
||||
monitor.StartMonitoring();
|
||||
|
||||
// Get diff immediately should return nothing.
|
||||
base::Value::List diff = monitor.GetDiff(kEmptyFilter);
|
||||
ASSERT_EQ(diff.size(), 0ull);
|
||||
|
||||
// Add more data to histogram.
|
||||
histogram1->Add(30);
|
||||
histogram1->Add(40);
|
||||
|
||||
histogram2->Add(20);
|
||||
|
||||
// Filter the query to only return "MonitorHistogram1", the baseline should
|
||||
// not change.
|
||||
diff = monitor.GetDiff("MonitorHistogram1");
|
||||
ASSERT_EQ(diff.size(), 1ull);
|
||||
std::string* header1 = diff[0].GetDict().FindString("header");
|
||||
EXPECT_EQ(*header1,
|
||||
"Histogram: MonitorHistogram1 recorded 2 samples, mean = 35.0");
|
||||
|
||||
|
||||
// Add more data to histogram2 and expect both samples after baseline to be
|
||||
// returned.
|
||||
histogram2->Add(10);
|
||||
diff = monitor.GetDiff("MonitorHistogram2");
|
||||
ASSERT_EQ(diff.size(), 1ull);
|
||||
std::string* header2 = diff[0].GetDict().FindString("header");
|
||||
EXPECT_EQ(*header2,
|
||||
"Histogram: MonitorHistogram2 recorded 2 samples, mean = 15.0");
|
||||
|
||||
// Add more data to histogram1 and expect that both histograms are still
|
||||
// returned for empty filter as they changed compared to the baseline.
|
||||
histogram1->Add(50);
|
||||
diff = monitor.GetDiff(kEmptyFilter);
|
||||
ASSERT_EQ(diff.size(), 2ull);
|
||||
|
||||
std::vector<std::string> headers;
|
||||
headers.push_back(*diff[0].GetDict().FindString("header"));
|
||||
headers.push_back(*diff[1].GetDict().FindString("header"));
|
||||
EXPECT_THAT(headers,
|
||||
testing::UnorderedElementsAre(
|
||||
"Histogram: MonitorHistogram1 recorded 3 samples, "
|
||||
"mean = 40.0",
|
||||
"Histogram: MonitorHistogram2 recorded 2 samples, "
|
||||
"mean = 15.0"));
|
||||
}
|
||||
|
||||
} // namespace content
|
||||
|
@ -12,7 +12,7 @@ found in the LICENSE file.
|
||||
<script type="module" src="histograms_internals.js"></script>
|
||||
<title>Histograms</title>
|
||||
</head>
|
||||
<h1>Histograms</h1>
|
||||
<h1><a href="#">Histograms</a></h1>
|
||||
<div id="accumulating_section">
|
||||
<button id="enable_monitoring">Switch to Monitoring Mode</button>
|
||||
<p>Stats accumulated from browser startup to previous page load;
|
||||
|
@ -249,6 +249,14 @@ function downloadHistograms() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleHashChange() {
|
||||
// In monitoring mode the updated histograms will be fetched by fetchDiff()
|
||||
// within 1s of changing URL and the proper filter will be applied.
|
||||
if (!inMonitoringMode) {
|
||||
requestHistograms();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the initial list of histograms.
|
||||
*/
|
||||
@ -266,4 +274,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
/**
|
||||
* Reload histograms when the "#abc" in "chrome://histograms/#abc" changes.
|
||||
*/
|
||||
window.onhashchange = requestHistograms;
|
||||
window.onhashchange = handleHashChange;
|
||||
|
Reference in New Issue
Block a user