blob: 22d28f6f7599361291cc320d33b2f31f32dc2d86 [file] [log] [blame]
// Copyright 2021 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.
#ifndef SRC_SYS_TEST_MANAGER_DEBUG_DATA_PROCESSOR_DATA_PROCESSOR_H_
#define SRC_SYS_TEST_MANAGER_DEBUG_DATA_PROCESSOR_DATA_PROCESSOR_H_
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/wait.h>
#include <lib/async/dispatcher.h>
#include <lib/debugdata/datasink.h>
#include <lib/zx/event.h>
#include <map>
#include <mutex>
#include <unordered_map>
#include <vector>
#include <fbl/unique_fd.h>
#include "abstract_data_processor.h"
#include "common.h"
#include "src/lib/fxl/synchronization/thread_annotations.h"
// represent debugdata::DumpFile as a map
using DumpFileMap = std::map<std::string, std::string>;
// key = data_sink name
using DataSinkMap = std::map<std::string, DumpFileMap>;
// key = test url
using TestDebugDataMap = std::map<std::string, DataSinkMap>;
// key = sink name, value = vector of VMOs published to debug data.
using SinkVMOMap = std::unordered_map<std::string, std::vector<zx::vmo>>;
// key = test_url
using TestSinkMap = std::map<std::string, SinkVMOMap>;
// Signal indicating more data has been added or marked complete.
const uint32_t STATE_DIRTY_SIGNAL = ZX_USER_SIGNAL_1;
static_assert(STATE_DIRTY_SIGNAL != DATA_FLUSHED_SIGNAL);
class DataProcessor : public AbstractDataProcessor {
public:
/// dir_fd: directory to write processed debug data to.
explicit DataProcessor(fbl::unique_fd dir_fd, async_dispatcher_t* dispatcher);
~DataProcessor() override;
/// Process data on internal dispacther.
void ProcessData(std::string test_url, DataSinkDump data_sink) override;
void FinishProcessing() override;
zx::unowned_event GetDataFlushedEvent() override;
/// Loads current summary.json if available, merges it with the passed map and writes the map back
/// to summary.json.
/// If current summary.json is corrupted, this function will crash to catch bugs early.
/// The format of summary.json is same as used in //zircon/system/ulib/runtest-utils.
/// Sample format:
/// {
/// "tests":[
/// {
/// "name":"test_url1.cm",
/// "data_sinks":{
/// "test1_sink1":[
/// {
/// "file":"path/path1",
/// "name":"name1"
/// },
/// {
/// "file":"path/path1_1",
/// "name":"name1_1"
/// }
/// ],
/// "test1_sink2":[
/// {
/// "file":"path/path2",
/// "name":"name2"
/// },
/// ],
/// ...
/// }
/// },
/// ...
/// ]//
/// }
static void WriteSummaryFile(fbl::unique_fd& fd, TestDebugDataMap debug_data_map);
private:
/// Container for information shared across threads.
class DataProcessorInner {
public:
explicit DataProcessorInner();
TestSinkMap TakeMapContents();
void AddData(std::string test_url, DataSinkDump data_sink_dump);
void FinishProcessing();
bool DataFinished();
void SignalFlushed();
zx::unowned_event GetEvent();
private:
std::mutex mutex_;
TestSinkMap data_sink_map_ FXL_GUARDED_BY(mutex_);
bool done_adding_data_ FXL_GUARDED_BY(mutex_);
zx::event idle_signal_event_;
};
/// State only accessed by the processing thread.
struct ProcessorState {
fbl::unique_fd dir_fd;
debugdata::DataSink data_sink;
explicit ProcessorState(fbl::unique_fd arg_dir_fd)
: dir_fd(std::move(arg_dir_fd)), data_sink(dir_fd) {}
};
/// Process data present in `data_sink_map_`. Returns true iff processing
/// all data is complete.
static bool ProcessDataInner(std::shared_ptr<DataProcessorInner> inner,
std::shared_ptr<ProcessorState> state);
std::shared_ptr<DataProcessorInner> inner_;
async_dispatcher_t* dispatcher_;
// This Wait is used to schedule work in the thread for dispatcher_ and should
// only be accessed from that thread.
std::shared_ptr<async::Wait> processor_wait_;
};
#endif // SRC_SYS_TEST_MANAGER_DEBUG_DATA_PROCESSOR_DATA_PROCESSOR_H_