blob: ab68fb215def9270bf179d27b52c2f277227376e [file] [log] [blame]
// Copyright 2025 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/performance/trace_manager/deferred_buffer_forwarder.h"
#include <lib/syslog/cpp/macros.h>
#include <lib/trace-engine/fields.h>
#include <filesystem>
#include <format>
namespace tracing {
namespace {
const char* kTraceDir = "/traces";
}
DeferredBufferForwarder::DeferredBufferForwarder(zx::socket destination)
: BufferForwarder(std::move(destination)) {
// In the event where trace_manager was killed while copying a trace, we might have an old file
// laying around. Remove them just in case.
std::filesystem::path dir_path = kTraceDir; // Current directory
for (auto& p : std::filesystem::directory_iterator(dir_path)) {
std::filesystem::remove(p);
}
std::chrono::time_point now = std::chrono::system_clock::now();
// TODO(https://fxbug.dev/446873535): Go back to naming these files with a timestamp again.
// std::string fname = std::format("trace_{}.fxt", now.time_since_epoch().count());
std::string fname = std::format("trace.fxt", now.time_since_epoch().count());
buffer_path_ = dir_path / fname;
buffer_file_ = fopen(buffer_path_.c_str(), "a+");
}
DeferredBufferForwarder::~DeferredBufferForwarder() {
Flush();
if (buffer_file_ != nullptr) {
fclose(buffer_file_);
}
// TODO(https://fxbug.dev/446873535): Go back to cleaning up trace files.
FX_LOGS(WARNING) << "Leaving file at " << buffer_path_ << " https://fxbug.dev/446873535";
// std::filesystem::remove(buffer_path_);
}
TransferStatus DeferredBufferForwarder::Flush() {
if (flushed_) {
return TransferStatus::kComplete;
}
if (buffer_file_ == nullptr) {
FX_LOGS(ERROR) << "Failed to open trace file: " << buffer_path_ << " for read!";
return TransferStatus::kWriteError;
}
if (fseek(buffer_file_, 0, SEEK_SET) != 0) {
FX_LOGS(ERROR) << "Failed to seek to beginning of: " << buffer_path_ << " for read!";
return TransferStatus::kWriteError;
}
const size_t BUFFER_SIZE = 4096;
uint8_t buffer[BUFFER_SIZE];
for (;;) {
size_t bytes_read = fread(buffer, sizeof(uint8_t), BUFFER_SIZE, buffer_file_);
if (bytes_read <= 0) {
break;
}
if (TransferStatus status = BufferForwarder::WriteBuffer({buffer, bytes_read});
status != TransferStatus::kComplete) {
return status;
}
}
flushed_ = true;
return TransferStatus::kComplete;
}
TransferStatus DeferredBufferForwarder::WriteBuffer(cpp20::span<const uint8_t> data) const {
if (buffer_file_ == nullptr) {
FX_LOGS(ERROR) << "Failed to open trace file for write: " << buffer_path_;
return TransferStatus::kWriteError;
}
while (!data.empty()) {
size_t actual = fwrite(data.data(), sizeof(uint8_t), data.size(), buffer_file_);
data = data.subspan(actual);
}
return TransferStatus::kComplete;
}
} // namespace tracing