21#include "sparta/events/GlobalOrderingPoint.hpp"
24#include "sparta/pipeViewer/Outputter.hpp"
25#include "sparta/pipeViewer/ClockFileWriter.hpp"
26#include "sparta/pipeViewer/LocationFileWriter.hpp"
27#include "sparta/simulation/TreeNodePrivateAttorney.hpp"
67 class CollectablesByClock
70 CollectablesByClock(
const Clock * clk,
74 switch(collection_phase)
76 case SchedulingPhase::Trigger:
78 (&ev_set_,
sparta::notNull(clk)->getName() +
"_auto_collection_event_trigger",
83 (&ev_set_,
sparta::notNull(clk)->getName() +
"_auto_collection_event_update",
88 (&ev_set_,
sparta::notNull(clk)->getName() +
"_auto_collection_event_portupdate",
93 (&ev_set_,
sparta::notNull(clk)->getName() +
"_auto_collection_event_flush",
98 (&ev_set_,
sparta::notNull(clk)->getName() +
"_auto_collection_event_collection",
103 (&ev_set_,
sparta::notNull(clk)->getName() +
"_auto_collection_event_tick",
108 (&ev_set_,
sparta::notNull(clk)->getName() +
"_auto_collection_event_posttick",
111 case SchedulingPhase::__last_scheduling_phase:
117 ev_collect_->setScheduleableClock(clk);
119 ev_collect_->setContinuing(
false);
123 enabled_ctns_.insert(ctn);
126 ev_collect_->schedule(sparta::Clock::Cycle(1));
130 enabled_ctns_.erase(ctn);
133 bool anyCollected()
const {
134 return !enabled_ctns_.empty();
137 void performCollection() {
143 for(
auto & ctn : enabled_ctns_) {
148 if(!enabled_ctns_.empty()) {
149 ev_collect_->schedule();
154 for(
auto ctn : enabled_ctns_) {
155 std::cout <<
'\t' << ctn->
getName() << std::endl;
161 std::unique_ptr<sparta::Scheduleable> ev_collect_;
162 std::set<CollectableTreeNode*> enabled_ctns_;
168 std::array<std::unique_ptr<CollectablesByClock>,
172 std::set<CollectableTreeNode*> registered_collectables_;
207 scheduler_(scheduler != nullptr ? scheduler : root_clk->
getScheduler()),
208 collector_events_(nullptr),
209 ev_heartbeat_(&collector_events_,
Collector::getName() +
"_heartbeat_event",
223 Vertex* post_tick_gop = dag->
getGOPoint(
"PostTick");
226 dag->unlink(ev_heartbeat_.
getVertex(), post_tick_gop);
227 post_tick_gop->precedes(ev_heartbeat_);
229 sparta_assert(root !=
nullptr,
"Pipeline Collection will not be able to create location file because it was passed a nullptr root treenode.");
230 sparta_assert(root->
isFinalized(),
"Pipeline collection cannot be constructed until the sparta tree has been finalized.");
232 sparta_assert(root_clk !=
nullptr,
"Cannot construct PipelineCollector because root clock is a nullptr");
233 sparta_assert(scheduler_->
isFinalized() ==
false,
"Pipeline Collection cannot be instantiated after scheduler finalization -- it creates events");
238 addClks = [&addClks,
this, &fastest_clk] (
const sparta::Clock* clk)
241 auto & u_p = clock_ctn_map_[clk];
243 u_p[i].reset(
new CollectablesByClock(clk,
static_cast<SchedulingPhase>(i)));
248 auto clk_period = child_clk->
getPeriod();
255 if(clk_period != 1 && (!fastest_clk || (clk_period < fastest_clk->getPeriod()))) {
256 fastest_clk = child_clk;
264 if(fastest_clk ==
nullptr){
265 fastest_clk = root_clk;
271 static const uint32_t heartbeat_multiplier = 200;
273 if (heartbeat_interval == 0)
276 heartbeat_interval = fastest_clk->
getPeriod() * heartbeat_multiplier;
277 heartbeat_interval = heartbeat_interval + (100 - (heartbeat_interval % 100));
286 filepath_ = filepath;
287 heartbeat_interval_ = heartbeat_interval;
288 closing_time_ = heartbeat_interval;
289 root_clk_ = root_clk;
298 "The PipelineCollector was not torn down properly. Before "
299 "tearing down the simulation tree, you must call "
300 "destroy() on the collector");
311 if(collection_active_) {
312 sparta_assert(writer_ !=
nullptr,
"Somehow collection is active, but we have a null writer");
313 for(
auto & ctn : registered_collectables_) {
314 if(ctn->isCollected()) {
315 ctn->closeRecord(
true);
319 registered_collectables_.clear();
321 collection_active_ =
false;
324 void reactivate(
const std::string& filepath)
327 "You can only reactivate the PipelineCollector after you destroy it");
328 filepath_ = filepath;
345 if(collection_active_ ==
false)
348 writer_.reset(
new pipeViewer::Outputter(filepath_, heartbeat_interval_));
351 writer_->writeIndex();
357 location_writer_.reset(
new pipeViewer::LocationFileWriter(filepath_));
364 const uint64_t num_hb = scheduler_->
getCurrentTick()/heartbeat_interval_;
366 while(cnt != num_hb) {
368 writer_->writeIndex();
369 last_heartbeat_ += heartbeat_interval_;
380 collection_active_ =
true;
383 *(location_writer_.get()) << (*starting_node);
387 recursiveCollect = [&recursiveCollect,
this] (
sparta::TreeNode* starting_node)
391 if(c_node !=
nullptr) {
393 registered_collectables_.insert(c_node);
399 recursiveCollect(node);
403 recursiveCollect(starting_node);
415 recursiveStopCollect = [&recursiveStopCollect,
this] (
sparta::TreeNode* starting_node) {
418 if(c_node !=
nullptr)
421 registered_collectables_.erase(c_node);
427 recursiveStopCollect(node);
430 recursiveStopCollect(starting_node);
432 bool still_active = !registered_collectables_.empty();
439 collection_active_ = still_active;
448 for(
auto & col : registered_collectables_) {
449 col->stopCollecting(
this);
451 registered_collectables_.clear();
469 auto ccm_pair = clock_ctn_map_.find(ctn->
getClock());
471 ccm_pair->second[
static_cast<uint32_t
>(collection_phase)]->enable(ctn);
487 auto ccm_pair = clock_ctn_map_.find(ctn->
getClock());
489 for(
auto & u_p : ccm_pair->second) {
502 return ++last_transaction_id_;
510 template<
class R_Type>
513 sparta_assert(collection_active_,
"The pipeline head must be running in order to write a transaction");
516 sparta_assert(dat.time_End <= (last_heartbeat_ + heartbeat_interval_));
524 || dat.time_Start >= closing_time_ - heartbeat_interval_,
525 "Attempted to write a pipeout record with exclusive start =("
526 << dat.time_Start <<
"), less than closing of previous interval"
527 << closing_time_ - heartbeat_interval_ );
533 writer_->writeTransaction<R_Type>(dat);
534 ++transactions_written_;
543 return transactions_written_;
557 return collection_active_;
585 void writeClockFile_()
590 pipeViewer::ClockFileWriter clock_writer(filepath_);
591 clock_writer << (*root_clk_);
597 void performHeartBeat_()
599 if(collection_active_) {
601 for(
auto & ctn : registered_collectables_) {
602 if(ctn->isCollected()) {
603 ctn->restartRecord();
608 writer_->writeIndex();
614 ev_heartbeat_.
schedule(heartbeat_interval_);
620 std::unique_ptr<pipeViewer::Outputter> writer_;
624 std::unique_ptr<pipeViewer::LocationFileWriter> location_writer_;
632 std::string filepath_;
636 uint64_t last_transaction_id_ = 0;
639 uint64_t transactions_written_ = 0;
643 uint64_t heartbeat_interval_ = 0;
649 Scheduler * scheduler_;
652 EventSet collector_events_;
653 UniqueEvent<SchedulingPhase::PostTick> ev_heartbeat_;
656 uint64_t closing_time_ = 0;
659 bool collection_active_ =
false;
File that defines the Clock class.
define a CollectableTreeNode type TreeNode.
Define a base Collector class.
File that defines the EventSet class.
A simple time-based, event precedence based scheduler.
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_abort(...)
Simple variatic assertion that will print a message to std::cerr and call std::terminate()
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define CREATE_SPARTA_HANDLER(clname, meth)
Basic Node framework in sparta device tree composite pattern.
File that defines the UniqueEvent class.
A representation of simulated time.
Period getPeriod() const
Returns the period of this clock in scheduler ticks.
Scheduler * getScheduler() const
Vertex * getGOPoint(const std::string &label)
Get the named GOP point; create it if not found.
Set of Events that a unit (or sparta::TreeNode, sparta::Resource) contains and are visible through a ...
virtual bool isFinalized() const
Is this node (and thus the entire tree above it) "finalized".
void scheduleRelativeTick(sparta::Scheduler::Tick rel_tick, sparta::Scheduler *scheduler) override final
Schedule at time rel_tick.
void setContinuing(bool continuing)
This event, if continuing == true, will keep the simulation running.
void setScheduler(Scheduler *sched)
Set the Scheduler of this Scheduleable, and set the local vertex_ to a new vertex from the Vertex Fac...
Vertex * getVertex()
get the internal Vertex of this scheduleable
void setScheduleableClock(const Clock *clk)
Set the clock and scheduler of this Scheduleable.
A class that lets you schedule events now and in the future.
DAG * getDAG() const
Get the internal DAG.
Tick getCurrentTick() const noexcept
The current tick the Scheduler is working on or just finished.
uint64_t Tick
Typedef for our unit of time.
bool isFinalized() const noexcept override
Is the scheduler finalized.
static const TreeNode::ChildrenVector & getAllChildren(const TreeNode &node)
Node in a composite tree representing a sparta Tree item.
const Clock * getClock() override
Walks up parents (starting with self) until a parent with an associated local clock is found,...
const std::string & getName() const override
Gets the name of this node.
A type of Event that uniquely schedules itself on the schedule within a single time quantum....
void schedule()
Schedule this event with its pre-set delay using the pre-set Clock.
An abstract type of TreeNode that has virtual calls to start collection on this node,...
void startCollecting(Collector *collector)
Method that tells this treenode that is now running collection.
bool isCollected() const
Determine whether or not this node has collection turned on or off.
void stopCollecting(Collector *collector)
Method that tells this treenode that is now not running collection.
A non-templated base class that all Collectors should inherit from.
A class that facilitates all universal pipeline collection operations such as outputting finalized re...
uint64_t numTransactionsWritten() const
Return the number of transactions that this singleton has passed to it's output. This is useful for t...
uint64_t getUniqueTransactionId()
Return a unique transaction id using a dummy counter.
void startCollection(sparta::TreeNode *starting_node)
Turn on collection for everything below a TreeNode. Recursively transverse the tree and turn on child...
PipelineCollector(const std::string &filepath, Scheduler::Tick heartbeat_interval, const sparta::Clock *root_clk, const sparta::TreeNode *root, Scheduler *scheduler=nullptr)
Instantiate the collector with required parameters before pipeline collection can occur.
void writeRecord(const R_Type &dat)
Output a finized transaction to our Outputter class.
void removeFromAutoCollection(CollectableTreeNode *ctn)
Remove the given CollectableTreeNode from collection.
bool isCollectionActive() const
Return true if the collector is actively collecting.
void stopCollection()
Stop pipeline collection on only those CollectableTreeNodes that this PipelineCollector was started w...
const std::string & getFilePath() const
void destroy()
Teardown the pipeline collector.
void addToAutoCollection(CollectableTreeNode *ctn, SchedulingPhase collection_phase=SchedulingPhase::Tick)
Add the CollectableTreeNode to auto collection.
Scheduler * getScheduler() const
void stopCollection(sparta::TreeNode *starting_node)
Stop pipeline collection on only those CollectableTreeNodes given.
Macros for handling exponential backoff.
T * notNull(T *p)
Ensures that a pointer is not null.
const uint32_t NUM_SCHEDULING_PHASES
The number of phases.
SchedulingPhase
The SchedulingPhases used for events (Tick, Update, PortUpdate, etc)
@ Update
Resources are updated in this phase.
@ PortUpdate
N-cycle Ports are updated in this phase.
@ Tick
Most operations (combinational logic) occurs in this phase.
@ Flush
Phase where flushing of pipelines, etc can occur.
@ PostTick
Operations such as post-tick pipeline collection occur here.
@ Collection
Pipeline collection occurs here.