blob: f49f3c32bfea76ba9b6c26f45b29b8ed651e942a [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/forensics/feedback_data/inspect_data_budget.h"
#include <lib/syslog/cpp/macros.h>
#include <algorithm>
#include <filesystem>
#include "src/developer/forensics/feedback_data/constants.h"
namespace forensics::feedback_data {
namespace {
// We target a 2MB final ZIP file. We give a budget between 4MB and 20MB for Inspect data, starting
// at 20MB.
const size_t kTargetZipSizeInBytes = 2 * 1024 * 1024;
const size_t kMinInspectDataBudgetInBytes = 4 * 1024 * 1024;
const size_t kMaxInspectDataBudgetInBytes = 20 * 1024 * 1024;
const size_t kStartingInspectDataBudgetInBytes = kMaxInspectDataBudgetInBytes;
} // namespace
InspectDataBudget::InspectDataBudget(const char* limit_data_flag_path, InspectNodeManager* node)
: inspect_node_(node) {
limit_data_flag_ = std::filesystem::exists(limit_data_flag_path);
inspect_budget_enabled_ =
inspect_node_->Get("/inspect_budget")
.CreateString("is_budget_enabled", limit_data_flag_ ? "true" : "false");
if (!limit_data_flag_) {
data_budget_ = std::nullopt;
return;
}
data_budget_ = kStartingInspectDataBudgetInBytes;
inspect_min_budget_ = inspect_node_->Get("/inspect_budget")
.CreateUint("min_input_budget_bytes", kMinInspectDataBudgetInBytes);
inspect_max_budget_ = inspect_node_->Get("/inspect_budget")
.CreateUint("max_input_budget_bytes", kMaxInspectDataBudgetInBytes);
inspect_target_size_ = inspect_node_->Get("/inspect_budget")
.CreateUint("target_snapshot_size_bytes", kTargetZipSizeInBytes);
}
void InspectDataBudget::UpdateBudget(
const std::map<std::string, ArchiveFileStats>& file_size_stats) {
std::string inspect_filename(kAttachmentInspect);
// No-op if data limiting is disabled or the Inspect file doesn't exist in the latest archive.
if (!limit_data_flag_ || file_size_stats.count(inspect_filename) == 0) {
return;
}
size_t previous_zip_size = 0;
for (const auto& [name, size] : file_size_stats) {
previous_zip_size += size.compressed_bytes;
}
// Online algorithm; there is no guarantee the same input will give us the same output. For
// simplicity we use only the last budget and its size output to calculate the new budget.
//
// Note: converges faster when the compressed portion of the inspect file is larger.
// Note: converges when the relationship between budget and snapshot is close to linearity.
const double ratio = (double)kTargetZipSizeInBytes / (double)previous_zip_size;
const size_t new_budget = (size_t)((double)data_budget_.value() * ratio);
data_budget_ = std::clamp(new_budget, kMinInspectDataBudgetInBytes, kMaxInspectDataBudgetInBytes);
// Add new budget data to Inspect.
auto entry =
inspect_node_->Get("/inspect_budget/last_ten_input_budget_previous_snapshot_size_bytes")
.CreateUintArray(std::to_string(next_reading_idx_++), 2);
entry.Set(0, data_budget_.value());
entry.Set(1, previous_zip_size);
inspect_last_ten_readings_.push_back(std::move(entry));
// We only keep the last 10 readings.
if (inspect_last_ten_readings_.size() > 10) {
inspect_last_ten_readings_.pop_front();
}
}
} // namespace forensics::feedback_data