The Sparta Modeling Framework
Loading...
Searching...
No Matches
Destination.hpp
1// <Destination> -*- C++ -*-
2
3#pragma once
4
5#include <cstddef>
6#include <cstdint>
7#include <iostream>
8#include <string>
9#include <ostream>
10#include <fstream>
11#include <sstream>
12#include <map>
13#include <mutex>
14#include <functional>
15#include <memory>
16#include <typeinfo>
17#include <utility>
18#include <vector>
19
20#include "sparta/log/Message.hpp"
25#include "sparta/utils/Utils.hpp"
26#include "sparta/log/MessageInfo.hpp"
27
28namespace sparta
29{
30 namespace log
31 {
54 {
55 public:
56
57 Destination(const Destination&) = delete;
58 Destination& operator=(const Destination&) = delete;
59
62 Destination(const Destination&& rhp) :
63 num_msgs_received_(rhp.num_msgs_received_),
64 num_msgs_written_(rhp.num_msgs_written_),
65 num_msg_duplicates_(rhp.num_msg_duplicates_),
66 last_seq_map_(rhp.last_seq_map_)
67 { }
68
71 num_msgs_received_(0),
72 num_msgs_written_(0),
73 num_msg_duplicates_(0)
74 { }
75
76 virtual ~Destination()
77 { }
78
83 template <std::size_t N>
84 bool compare(const char (& arg)[N]) const {
85 // Defer to subclass' compareStrings
86 return compareStrings(std::string(arg));
87 }
88
93 bool compare(const char *& arg) const {
94 // Defer to subclass' compareStrings
95 return compareStrings(std::string(arg));
96 }
97
101 bool compare(const std::string& arg) const {
102 // Defer to subclass' compareStrings
103 return compareStrings(arg);
104 }
105
109 bool compare(const std::ostream& arg) const {
110 return compareOstreams(arg);
111 }
112
119 template <typename T>
120 bool compare(const T&) const {
121 throw SpartaException("Logging destination does not now how to compare a Destination "
122 "instance with type: ") << demangle(typeid(T).name());
123 }
124
125 // Virtual Comparisons for matching destinations
126
131 virtual bool compareStrings(const std::string&) const {
132 return false;
133 }
134
139 virtual bool compareOstreams(const std::ostream&) const {
140 return false;
141 }
142
152 virtual std::string stringize(bool pretty=false) const = 0;
153
155 void write(const sparta::log::Message& msg) {
156 std::lock_guard<std::mutex> lock(write_mutex_);
157
158 ++num_msgs_received_;
159
160 // Filter by sequence. Get last sequence ID on this message's thread
161 seq_num_type last_seq = getLastSequenceNum_(msg.info.thread_id);
162 if(msg.info.seq_num <= last_seq){
163 // Duplicate (same msg from a different tap), do not write
164 ++num_msg_duplicates_;
165 return;
166 }
167
168 ++num_msgs_written_;
169 write_(msg);
170
171 last_seq_map_[msg.info.thread_id] = msg.info.seq_num; // Update latest sequence
172 };
173
178 uint64_t getNumMessagesReceived() const { return num_msgs_received_; }
179
184 uint64_t getNumMessagesWritten() const { return num_msgs_written_; }
185
198 uint64_t getNumMessageDuplicates() const { return num_msg_duplicates_; }
199
200 private:
201
204 seq_num_type getLastSequenceNum_(thread_id_type tid) const {
205
206 auto itr = last_seq_map_.find(tid);
207 if(itr != last_seq_map_.end()){
208 return itr->second;
209 }
210 return -1;
211 };
212
218 virtual void write_(const sparta::log::Message& msg) = 0;
219
220
221 uint64_t num_msgs_received_;
222 uint64_t num_msgs_written_;
223 uint64_t num_msg_duplicates_;
224
225 std::map<thread_id_type, seq_num_type> last_seq_map_;
226
227 std::mutex write_mutex_;
228 };
229
234 class Formatter {
235 protected:
236 std::ostream& stream_;
237
238 public:
239
244 struct Info {
245 const char* const extension;
246 const std::string extname;
247 std::function<Formatter* (std::ostream&)> factory;
248 };
249
255 Formatter(std::ostream& stream) :
256 stream_(stream)
257 { }
258
260 virtual ~Formatter() { }
261
265 virtual void write(const sparta::log::Message& msg) = 0;
266
270 virtual void writeHeader(const SimulationInfo& sim_info) = 0;
271
283 static const Info* FORMATTERS;
284 };
285
288 public:
289 VerboseFormatter(std::ostream& stream) :
290 Formatter(stream)
291 { }
292
297 void write(const sparta::log::Message& msg) override {
298 // Replace any \n's with nothing
299 stream_ << msg.info << copyWithReplace(msg.content, '\n', "") << std::endl;
300 stream_.flush();
301 }
302
303 void writeHeader(const SimulationInfo& sim_info) override {
304 sim_info.write(stream_, "#", "\n");
305 stream_.flush();
306 }
307 };
308
314 public:
315 DefaultFormatter(std::ostream& stream) :
316 Formatter(stream)
317 { }
318
322 void write(const sparta::log::Message& msg) override;
323
324 void writeHeader(const SimulationInfo& sim_info) override {
325 sim_info.write(stream_, "#", "\n");
326 stream_.flush();
327 }
328 };
329
334 class BasicFormatter : public Formatter {
335 public:
336 BasicFormatter(std::ostream& stream) :
337 Formatter(stream)
338 { }
339
340 void write(const sparta::log::Message& msg) override {
341 stream_ << msg.info.origin.getLocation() << ": "
342 << *msg.info.category << ": "
343 << copyWithReplace(msg.content, '\n', "") << std::endl;
344 stream_.flush();
345 }
346
347 void writeHeader(const SimulationInfo& sim_info) override {
348 sim_info.write(stream_, "#", "\n");
349 stream_.flush();
350 }
351 };
352
356 class RawFormatter : public Formatter {
357 public:
358 RawFormatter(std::ostream& stream) :
359 Formatter(stream)
360 { }
361
362 void write(const sparta::log::Message& msg) override {
363 stream_ << copyWithReplace(msg.content, '\n', "") << std::endl;
364 stream_.flush();
365 }
366
367 void writeHeader(const SimulationInfo& sim_info) override {
368 sim_info.write(stream_, "#", "\n");
369 stream_.flush();
370 }
371 };
372
384 template <typename DestType>
386 {
387 };
388
394 template <>
395 class DestinationInstance<std::ostream> : public Destination
396 {
397 std::ostream& stream_;
398 DefaultFormatter fmt_;
399
400 public:
401
402 DestinationInstance(std::ostream& stream) :
403 stream_(stream),
404 fmt_(stream_)
405 {
406 if(stream.good() == false){
407 throw SpartaException("stream must be a good() ostream");
408 }
409 }
410
411 virtual bool compareOstreams(const std::ostream& o) const override {
412 return &o == &stream_;
413 }
414
415 // From TreeNode
416 virtual std::string stringize(bool pretty=false) const override {
417 (void) pretty;
418 std::stringstream ss;
419 ss << "<" << "destination ostream=";
420 if(&stream_ == &std::cout){
421 ss << "cout";
422 }else if(&stream_ == &std::cerr){
423 ss << "cerr";
424 }else{
425 ss << &stream_;
426 }
427 ss << " rcv="
428 << getNumMessagesReceived() << " wrote=" << getNumMessagesWritten()
429 << " dups=" << getNumMessageDuplicates() << ">";
430 return ss.str();
431 }
432
433 private:
434
435 virtual void write_(const sparta::log::Message& msg) override {
436 fmt_.write(msg);
437 };
438 };
439
449 template <>
450 class DestinationInstance<std::string> : public Destination
451 {
452 std::ofstream stream_;
453 const std::string filename_;
454 std::unique_ptr<Formatter> formatter_;
455 const Formatter::Info* fmtinfo_;
456
457 public:
458
465 DestinationInstance(const std::string& filename) :
466 stream_(filename, std::ofstream::out), // write mode
467 filename_(filename)
468 {
469 if(stream_.good() == false){
470 throw SpartaException("Failed to open logging destination file for append \"")
471 << filename << "\"";
472 }
473
474 // Throw on write errors
475 stream_.exceptions(std::ostream::eofbit | std::ostream::badbit | std::ostream::failbit | std::ostream::goodbit);
476
477 fmtinfo_ = Formatter::FORMATTERS;
478 while(true){
479 if(nullptr == fmtinfo_->extension){
480 break; // End of the list. Use this formatter
481 }
482 std::string ext = fmtinfo_->extension;
483 size_t pos = filename.find(ext);
484 if(pos != std::string::npos && pos == filename.size() - ext.size()){
485 break; // Use this fmtinfo_->factory to construct
486 }
487 ++fmtinfo_;
488 }
489 if(nullptr == fmtinfo_){
490 throw SpartaException("No formatters defined in FORMATTERS ")
491 << "list for file-based destination instance. "
492 << "Cannot open file \"" << filename << "\"";
493 }
494 formatter_.reset(fmtinfo_->factory(stream_));
495 sparta_assert(formatter_ != nullptr);
496
497 formatter_->writeHeader(SimulationInfo::getInstance());
498 }
499
500 virtual bool compareStrings(const std::string& filename) const override {
501 return filename == filename_;
502 }
503
504 // From TreeNode
505 virtual std::string stringize(bool pretty=false) const override {
506 (void) pretty;
507 std::stringstream ss;
508 ss << "<" << "destination file=\"" << filename_ << "\" format=\""
509 << fmtinfo_->extname << "\" ext=\"";
510 if(nullptr == fmtinfo_->extension){
511 ss << "(default)";
512 }else{
513 ss << fmtinfo_->extension;
514 }
515 ss << "\" ostream="
516 << &stream_ << " rcv=" << getNumMessagesReceived()
517 << " wrote=" << getNumMessagesWritten()
518 << " dups=" << getNumMessageDuplicates() << ">";
519 return ss.str();
520 }
521
522 private:
523
524 virtual void write_(const sparta::log::Message& msg) override {
525 formatter_->write(msg);
526 };
527 };
528
529
536 {
537 public:
538
540 typedef std::vector<std::unique_ptr<Destination>> DestinationVector;
541
566 template <class DestT>
567 static Destination* getDestination(DestT& arg) {
568 for(std::unique_ptr<Destination>& d : dests_){
569 // Overload for Destination::compare(DestT&) must exist. c-string type is typically const char[N]
570 if(d->compare(arg)){
571 return d.get();
572 }
573 }
574
575 dests_.emplace_back(createDestination(arg));
576 return dests_.back().get();
577 }
578
580 template <std::size_t N>
581 static Destination* createDestination(const char (&arg)[N]) {
582 return new DestinationInstance<std::string>(arg);
583 }
584
586 static Destination* createDestination(const char *& arg) {
587 return new DestinationInstance<std::string>(arg);
588 }
589
590 template <class DestT>
591 static Destination* createDestination(const DestT& arg) {
592 return new DestinationInstance<DestT>(arg);
593 }
594
595 template <class DestT>
596 static Destination* createDestination(DestT& arg) {
597 return new DestinationInstance<DestT>(arg);
598 }
599
604 return dests_;
605 }
606
611 static uint32_t getNumDestinations() {
612 return dests_.size();
613 }
614
619 static std::ostream& dumpDestinations(std::ostream& o, bool pretty=false) {
620 (void) pretty;
621 for(auto& d : dests_){
622 o << " " << d->stringize() << std::endl;
623 }
624
625 return o;
626 }
627
634 static std::ostream& dumpFileExtensions(std::ostream& o, bool pretty=false) {
635 (void) pretty;
637 while(true){
638 if(nullptr == finf->extension){
639 o << " " << "(default) -> " << finf->extname << std::endl;
640 break; // End of the list
641 }
642 o << " \"" << finf->extension << "\" -> " << finf->extname << std::endl;
643 ++finf;
644 }
645
646 return o;
647 }
648
649 private:
650
652 static DestinationVector dests_;
653 };
654
655 } // namespace log
656} // namespace sparta
657
659inline std::ostream& operator<< (std::ostream& out, sparta::log::Destination const & d){
660 out << d.stringize();
661 return out;
662}
663
664inline std::ostream& operator<< (std::ostream& out, sparta::log::Destination const * d){
665 if(d == 0){
666 out << "null";
667 }else{
668 out << d->stringize();
669 }
670 return out;
671}
672
Simulation information container for tracking the status of the simulation.
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
Basic Node framework in sparta device tree composite pattern.
Contains information describing the simulation instance for the purpose of identifying the simulation...
void write(StreamType &o, const std::string &line_start="# ", const std::string &line_end="\n", bool show_field_names=true) const
Write this information to an ostream.
static SimulationInfo & getInstance()
Gets the SimulationInfo singleton instance.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
std::string getLocation() const override final
Formatter including only a few bits of the most relevant message information.
void write(const sparta::log::Message &msg) override
Write a log message to a report.
void writeHeader(const SimulationInfo &sim_info) override
Write a header to a newly-opened report.
Formatter that writes most message information, but excludes thread/sequence.
void writeHeader(const SimulationInfo &sim_info) override
Write a header to a newly-opened report.
void write(const sparta::log::Message &msg) override
Writes a moderate amount of info to output stream.
virtual std::string stringize(bool pretty=false) const override
Create a string representation of this Destination.
virtual bool compareOstreams(const std::ostream &o) const override
Returns true if the destination behind this interface was constructed with the ostream o.
virtual bool compareStrings(const std::string &filename) const override
Returns true if the destination behind this interface was constructed with the string s.
virtual std::string stringize(bool pretty=false) const override
Create a string representation of this Destination.
DestinationInstance(const std::string &filename)
Constructs the destination with the given filename. Data will be written in a format based on the ext...
A destination where log messages go to be written to a file or other ostream. Attempts to prevent dup...
Manages a set of destinations representing files or streams. All log messages will be written to at l...
static Destination * createDestination(const char(&arg)[N])
createDestination overload for handling const char[] strings
static const DestinationVector & getDestinations()
Returns vector containing all destinations.
static std::ostream & dumpDestinations(std::ostream &o, bool pretty=false)
Dumps the destinations known by the destination manager to an ostream with each destination on a sepa...
std::vector< std::unique_ptr< Destination > > DestinationVector
Vector of destination pointers.
static uint32_t getNumDestinations()
Returns number of destinations contained in the DestinationManager.
static Destination * createDestination(const char *&arg)
createDestination overload for handling char* strings
static std::ostream & dumpFileExtensions(std::ostream &o, bool pretty=false)
Dumps the supported file extensions for destinations instantiated through the destination manager bas...
static Destination * getDestination(DestT &arg)
Requests an existing Destination* from the manager and allocates a new one if it does not yet have a ...
Generic Logging destination stream interface which writes sparta::log::Message structures to some out...
uint64_t getNumMessagesReceived() const
Get the total number of messages logged through this destination.
uint64_t getNumMessageDuplicates() const
Gets the total number of times that a message has arrived at this destination after already having be...
virtual bool compareOstreams(const std::ostream &) const
Returns true if the destination behind this interface was constructed with the ostream o.
bool compare(const T &) const
Operator= for for other unknown types.
bool compare(const char *&arg) const
Comparison of destination for const char[]. Uses std::string comparison.
bool compare(const std::string &arg) const
Comparison of destination for std::string.
void write(const sparta::log::Message &msg)
bool compare(const std::ostream &arg) const
Handle Destination::operator== on ostreams.
virtual bool compareStrings(const std::string &) const
Returns true if the destination behind this interface was constructed with the string s.
bool compare(const char(&arg)[N]) const
Comparison of destination for const char[]. Uses std::string comparison.
Destination()
Default constructor.
uint64_t getNumMessagesWritten() const
Gets the total number of messages received by this destination and then written to the actual output ...
virtual std::string stringize(bool pretty=false) const =0
Create a string representation of this Destination.
Destination(const Destination &&rhp)
File writer formatting interface. Subclsases can format for different file types (e....
Formatter(std::ostream &stream)
Constructor.
virtual ~Formatter()
Destructor.
static const Info * FORMATTERS
Formatter list terminated with a Info having an empty name which is interpreted as the default format...
virtual void writeHeader(const SimulationInfo &sim_info)=0
Write a header to a newly-opened report.
virtual void write(const sparta::log::Message &msg)=0
Write a log message to a report.
Formatter including no meta-data from the message.
void write(const sparta::log::Message &msg) override
Write a log message to a report.
void writeHeader(const SimulationInfo &sim_info) override
Write a header to a newly-opened report.
Formatter that writes all message information.
void write(const sparta::log::Message &msg) override
Writes every piece of information associated with the log message.
void writeHeader(const SimulationInfo &sim_info) override
Write a header to a newly-opened report.
int64_t seq_num_type
Sequence number of a message within a thread ID. Signed so that initial state can be -1.
uint32_t thread_id_type
Identifies a thread in the simulator kernel.
Macros for handling exponential backoff.
std::string copyWithReplace(const std::string &s, char from, const std::string &to)
Copies from 1 string to another with replacement of a single character with a string.
Definition Utils.hpp:282
std::string demangle(const std::string &name) noexcept
Demangles a C++ symbol.
Definition Utils.hpp:203
Formatter type description. Used in a table to describe various formatter sublasses.
seq_num_type seq_num
Sequence number of message within thread.
thread_id_type thread_id
Thread ID of source.
category_id_type category
Category with which this message was created. Must not be NULL.
TreeNode const & origin
Node from which message originated.
Contains a logging message header and content.
Definition Message.hpp:18