/************************************************************************* * * Copyright (c) 2023 Fabian Posch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * ************************************************************************** */ #ifndef __PIPELINE_ARTIFACT_H__ #define __PIPELINE_ARTIFACT_H__ #include #include #include #include #include #include namespace pl { /** * @brief Representation of different artifact types */ enum class ArtifactType {UNKNOWN, ACT, SIM_CONFIG, SIGLIST, SIM_OUTPUT}; static std::unordered_map art_type_str = { {"unknown", ArtifactType::UNKNOWN}, {"act", ArtifactType::ACT}, {"testcases", ArtifactType::SIM_CONFIG}, {"sig_list", ArtifactType::SIGLIST}, {"sim_output", ArtifactType::SIM_OUTPUT} }; inline std::string to_string(ArtifactType const &value) { std::string str = "unknown"; for (auto& it : art_type_str) { if (it.second == value) { str = it.first; break; } } return str; }; inline std::ostream& operator<<(std::ostream& os, ArtifactType const &rhs) { os << to_string(rhs); return os; }; /** List of artifact names as well as types */ typedef std::vector> artifact_list; /** * @brief An artifact is a data point which can be consumed or produced by a pipeline module */ class Artifact { public: /** * @brief Construct a new blank Artifact * */ Artifact() = default; /** * @brief Get the type of the artifact the object is holding. * * Substitute for getting the object type * * @return ArtifactType */ virtual ArtifactType get_type() { return ArtifactType::UNKNOWN; }; /** * @brief Get the content of the artifact * * @tparam T Content type the artifact is holding * @return T Content of the artifact */ template T get_content(); /** * @brief Get the number of elements in this artifact * * This is mostly relevant when uploading an artifact to the database cluster. * * @return long The number of elements in this artifact */ virtual long get_size() = 0; /** * @brief Inform a tool whether this artifact can be handled by multiple nodes * * By default, one artifact should only be handled once. However, there might be * situations where multiple nodes can handle a single artifact. This could for example * be a situation where a simulation for a design has a coverage model for constrained * random testing. In this case we want to cover everything as fast as possible and * simulation can be distributed. * * @return true The artifact can be handled by multiple nodes * @return false The artifact cannot be handled by multiple nodes */ bool parallelizable() { return false; }; }; /** * @brief ACT design artifact */ class ActArtifact: public Artifact { public: /** * @brief Construct a new ACT design artifact * * @param design The design object the artifact should point to */ ActArtifact(std::shared_ptr design) { this->design = design; }; /** * @brief Get the content of the artifact * * @return std::shared_ptr Pointer to the artifact's design file. */ std::shared_ptr get_content() { return design; }; /** * @brief Returns the type of this artifact, which is ACT. * * @return ArtifactType Will return the ACT artifact type. */ ArtifactType get_type() override { return ArtifactType::ACT; }; /** * @brief Get the number of elements in this artifact, which is 1 per definition * * @return long */ long get_size() override { return 1; }; private: std::shared_ptr design; }; /** * @brief Struct to capture one testcase. */ struct testcase_t { /** Commands to be executed for this testcase */ std::vector commands; /** Top process for the simulation */ std::string top; /** This simulation should be run by multiple noes */ bool parallelizable; }; /** * @brief Artifact containing one or more configurations for actsim */ class SimConfigArtifact: public Artifact { public: SimConfigArtifact() = default; SimConfigArtifact(bool has_reference) { this->has_reference_ = has_reference; }; /** * @brief Get the content of the artifact * * @return std::vector Vector of all generated testcase structures */ std::vector& get_content() { return testcases; }; /** * @brief Add a testcase to the artifact * * @param testcase */ inline void add_testcase(testcase_t testcase) { this->testcases.emplace_back(testcase); }; /** * @brief Returns the type of this artifact, which is SIM_CONFIG. * * @return ArtifactType Will return the SIM_CONFIG artifact type. */ ArtifactType get_type() override { return ArtifactType::SIM_CONFIG; }; /** * @brief Get the number of testcases stored in this artifact * * @return long The size of the testcase vector */ long get_size() override { return testcases.size(); }; const bool& has_reference = has_reference_; /** * @brief Can this simulation be handled by multiple nodes * * By default, one artifact should only be handled once. However, there might be * situations where multiple nodes can handle a single artifact. This could for example * be a situation where a simulation for a design has a coverage model for constrained * random testing. In this case we want to cover everything as fast as possible and * simulation can be distributed. * * @return true The simulation can be handled by multiple nodes * @return false The simulation cannot be handled by multiple nodes */ bool parallelizable() { if (this->testcases.size() != 1) return false; return this->testcases.front().parallelizable; }; private: bool has_reference_; std::vector testcases; }; /** Reference to a signal in an ACT design */ typedef std::string signal_t; /** * @brief Artifact containing a list of signals */ class SignalListArtifact: public Artifact { public: /** * @brief Get the content of the artifact * * @return std::vector Vector of all captured signals structures */ std::vector get_content() { return signals; }; /** * @brief Add a signal to the artifact * * @param testcase */ inline void add_signal(signal_t signal) { this->signals.emplace_back(signal); }; /** * @brief Returns the type of this artifact, which is SIGLIST. * * @return ArtifactType Will return the SIGLIST artifact type. */ ArtifactType get_type() override { return ArtifactType::SIGLIST; }; /** * @brief Get the number of signals stored in this artifact * * @return long The size of the signals vector */ long get_size() override { return signals.size(); }; private: std::vector signals; }; /** * @brief Artifact containing simulator output from actsim */ class SimOutputArtifact: public Artifact { public: SimOutputArtifact() {}; SimOutputArtifact(const std::vector& sim_log, const std::vector& error_log) { this->sim_log = sim_log; this->sim_err_log = error_log; has_content_ = true; }; /** * @brief Get the content of the artifact * * @return std::vector Vector of all generated simulator output lines */ inline std::pair&, std::vector&> get_content() { return {sim_log, sim_err_log}; }; inline std::vector& get_output_token_timings() { return output_token_timings; }; inline void set_output_token_timings(std::vector timings) { this->output_token_timings = timings; }; /** * @brief Add a log line to the artifact * * @param log_line */ inline void add_log_output(std::string log_line) { this->sim_log.emplace_back(log_line); has_content_ = true; }; /** * @brief Add a error log line to the artifact * * @param log_line */ inline void add_err_output(std::string log_line) { this->sim_err_log.emplace_back(log_line); has_content_ = true; }; inline void clear_logs() { // save the size size_ = this->sim_err_log.size() + this->sim_log.size(); this->sim_err_log.clear(); this->sim_log.clear(); has_content_ = false; }; inline void add_output_token_timing(uint32_t timing) { this->output_token_timings.emplace_back(timing); }; /** * @brief Returns the type of this artifact, which is SIM_OUTPUT. * * @return ArtifactType Will return the SIM_OUTPUT artifact type. */ inline ArtifactType get_type() override { return ArtifactType::SIM_OUTPUT; }; /** * @brief Get the number of log lines stored in this artifact * * @return long The size of the log lines vector */ inline long get_size() override { if (has_content_) {return sim_log.size();} else {return size_;} }; inline void set_size(long size) { if (!has_content_) this->size_ = size; }; const bool& fault_timing_deviation = fault_timing_deviation_; const bool& fault_value = fault_value_; const bool& fault_coding = fault_coding_; const bool& fault_glitch = fault_glitch_; const bool& fault_deadlock = fault_deadlock_; const bool& fault_token_count = fault_token_count_; const int& output_tokens = output_tokens_; inline void set_fault_timing_deviation (bool fault_timing_deviation) { this->fault_timing_deviation_ = fault_timing_deviation; }; inline void set_fault_value (bool fault_value) { this->fault_value_ = fault_value; }; inline void set_fault_coding (bool fault_coding) { this->fault_coding_ = fault_coding; }; inline void set_fault_glitch (bool fault_glitch) { this->fault_glitch_ = fault_glitch; }; inline void set_fault_deadlock (bool fault_deadlock) { this->fault_deadlock_ = fault_deadlock; }; inline void set_fault_token_count (bool fault_token_count) { this->fault_token_count_ = fault_token_count; }; inline void set_output_tokens(int output_tokens) { this->output_tokens_ = output_tokens; }; private: std::vector sim_log; std::vector sim_err_log; std::vector output_token_timings; bool fault_timing_deviation_ = false; bool fault_value_ = false; bool fault_coding_ = false; bool fault_glitch_ = false; bool fault_deadlock_ = false; bool fault_token_count_ = false; int output_tokens_; long size_ = 0; bool has_content_ = false; }; }; #endif