/************************************************************************* * * 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 "util.h" 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(); /** * @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() { 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(); 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 */ void add_testcase(testcase_t 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() { 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 */ void add_signal(signal_t 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() { return signals.size(); }; private: std::vector signals; }; /** * @brief Artifact containing simulator output from actsim */ class SimOutputArtifact: public Artifact { public: SimOutputArtifact(const std::vector& sim_log, const std::vector& error_log); /** * @brief Get the content of the artifact * * @return std::vector Vector of all generated simulator output lines */ std::pair&, std::vector&> get_content() { return {sim_log, sim_err_log}; }; /** * @brief Add a log line to the artifact * * @param log_line */ void add_log_output(std::string log_line); /** * @brief Add a error log line to the artifact * * @param log_line */ void add_err_output(std::string log_line); /** * @brief Returns the type of this artifact, which is SIM_OUTPUT. * * @return ArtifactType Will return the SIM_OUTPUT artifact type. */ 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 */ long get_size() { return sim_log.size(); }; private: std::vector sim_log; std::vector sim_err_log; }; }; #endif