diff --git a/include/sta/Error.hh b/include/sta/Error.hh index e24db0de..760ff819 100644 --- a/include/sta/Error.hh +++ b/include/sta/Error.hh @@ -17,7 +17,7 @@ #pragma once #include -#include "DisallowCopyAssign.hh" + #include "Report.hh" namespace sta { @@ -31,6 +31,16 @@ public: virtual const char *what() const noexcept = 0; }; +class ExceptionMsg : public Exception +{ +public: + ExceptionMsg(const char *msg); + virtual const char *what() const noexcept; + +private: + string msg_; +}; + class ExceptionLine : public Exception { public: diff --git a/include/sta/Report.hh b/include/sta/Report.hh index 6285d372..4754ee69 100644 --- a/include/sta/Report.hh +++ b/include/sta/Report.hh @@ -47,27 +47,7 @@ public: va_list args); void print(const string *str); void print(const string &str); - - // Print to debug stream (same as output stream). - virtual void printDebug(const char *fmt, ...) - __attribute__((format (printf, 2, 3))); - virtual void vprintDebug(const char *fmt, - va_list args); - - // Print to error stream. - // Return the number of characters written. - virtual size_t printError(const char *buffer, - size_t length); - virtual void printError(const char *fmt, ...) - __attribute__((format (printf, 2, 3))); - virtual void vprintError(const char *fmt, - va_list args); - - // Print to warning stream (same as error stream). - virtual void printWarn(const char *fmt, ...) - __attribute__((format (printf, 2, 3))); - virtual void vprintWarn(const char *fmt, - va_list args); + virtual void flush() {} //////////////////////////////////////////////////////////////// @@ -137,12 +117,15 @@ protected: // Return the number of characters written. virtual size_t printConsole(const char *buffer, size_t length) = 0; - // Primitive to print warning, error, critical and debug output. - // Return the number of characters written. - virtual size_t printErrorConsole(const char *buffer, - size_t length) = 0; + void printToBuffer(const char *fmt, + ...); void printToBuffer(const char *fmt, va_list args); + void printToBufferAppend(const char *fmt, + ...); + void printToBufferAppend(const char *fmt, + va_list args); + void printBuffer(); void redirectStringPrint(const char *buffer, size_t length); diff --git a/include/sta/ReportTcl.hh b/include/sta/ReportTcl.hh index ea16b9b1..92260856 100644 --- a/include/sta/ReportTcl.hh +++ b/include/sta/ReportTcl.hh @@ -46,7 +46,7 @@ public: protected: virtual size_t printConsole(const char *buffer, size_t length); - virtual size_t printErrorConsole(const char *buffer, size_t length); + void flush(); private: DISALLOW_COPY_AND_ASSIGN(ReportTcl); diff --git a/search/Genclks.cc b/search/Genclks.cc index 4252c90f..dd815678 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -328,8 +328,8 @@ Genclks::ensureMaster(Clock *gclk) iter.enqueueAdjacentVertices(vertex); } if (master_clk_count > 1) - report_->error(11, "generated clock %s is in the fanout of multiple clocks.", - gclk->name()); + report_->warn(11, "generated clock %s is in the fanout of multiple clocks.", + gclk->name()); } else { Pin *src_pin = gclk->srcPin(); @@ -379,10 +379,10 @@ Genclks::ensureMaster(Clock *gclk) } } if (master_clk_count > 1) - report_->error(12, - "generated clock %s pin %s is in the fanout of multiple clocks.", - gclk->name(), - network_->pathName(src_pin)); + report_->warn(12, + "generated clock %s pin %s is in the fanout of multiple clocks.", + gclk->name(), + network_->pathName(src_pin)); } } } diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index bbffc66a..992e5ab4 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -1383,7 +1383,7 @@ WritePathSpice::writeSubckts() report_->error(28, "The following subkcts are missing from %s", lib_subckt_filename_); for (const char *cell_name : path_cell_names) - report_->printError(" %s\n", cell_name); + report_->print(" %s\n", cell_name); } } else { diff --git a/tcl/Exception.i b/tcl/Exception.i index 6b786981..269913b7 100644 --- a/tcl/Exception.i +++ b/tcl/Exception.i @@ -22,7 +22,7 @@ try { $function } catch (std::bad_alloc &) { fprintf(stderr, "Error: out of memory.\n"); - exit(0); + exit(1); } catch (std::exception &excp) { Tcl_ResetResult(interp); diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 64135dca..6d6d522a 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -324,11 +324,14 @@ pushPowerResultFloats(PowerResult &power, //////////////////////////////////////////////////////////////// void -tclError(Tcl_Interp *interp, - const char *msg, - const char *arg) +tclArgError(Tcl_Interp *interp, + const char *msg, + const char *arg) { - char *error = stringPrint(msg, arg); + // Swig does not add try/catch around arg parsing so this cannot use Report::error. + string error_msg = "Error: "; + error_msg += msg; + char *error = stringPrint(error_msg.c_str(), arg); Tcl_SetResult(interp, error, TCL_VOLATILE); stringDelete(error); } @@ -867,7 +870,7 @@ using namespace sta; floats->push_back(static_cast(value)); else { delete floats; - tclError(interp, "Error: %s is not a floating point number.", arg); + tclArgError(interp, "%s is not a floating point number.", arg); return TCL_ERROR; } } @@ -915,7 +918,7 @@ using namespace sta; ints->push_back(value); else { delete ints; - tclError(interp, "Error: %s is not an integer.", arg); + tclArgError(interp, "%s is not an integer.", arg); return TCL_ERROR; } } @@ -930,7 +933,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclError(interp, "Error: %s not min or max.", arg); + tclArgError(interp, "%s not min or max.", arg); return TCL_ERROR; } } @@ -950,7 +953,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclError(interp, "Error: %s not min, max or min_max.", arg); + tclArgError(interp, "%s not min, max or min_max.", arg); return TCL_ERROR; } } @@ -965,7 +968,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclError(interp, "Error: %s not min, max or min_max.", arg); + tclArgError(interp, "%s not min, max or min_max.", arg); return TCL_ERROR; } } @@ -986,7 +989,7 @@ using namespace sta; || stringEqual(arg, "max")) $1 = MinMax::max(); else { - tclError(interp, "Error: %s not setup, hold, min or max.", arg); + tclArgError(interp, "%s not setup, hold, min or max.", arg); return TCL_ERROR; } } @@ -1005,7 +1008,7 @@ using namespace sta; || stringEqual(arg, "min_max")) $1 = SetupHoldAll::all(); else { - tclError(interp, "Error: %s not setup, hold, setup_hold, min, max or min_max.", arg); + tclArgError(interp, "%s not setup, hold, setup_hold, min, max or min_max.", arg); return TCL_ERROR; } } @@ -1018,7 +1021,7 @@ using namespace sta; if (early_late) $1 = early_late; else { - tclError(interp, "Error: %s not early/min or late/max.", arg); + tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg); return TCL_ERROR; } } @@ -1031,7 +1034,7 @@ using namespace sta; if (early_late) $1 = early_late; else { - tclError(interp, "Error: %s not early/min, late/max or early_late/min_max.", arg); + tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg); return TCL_ERROR; } } @@ -1046,7 +1049,7 @@ using namespace sta; else if (stringEq(arg, "cell_check")) $1 = TimingDerateType::cell_check; else { - tclError(interp, "Error: %s not clk or data.", arg); + tclArgError(interp, "%s not clk or data.", arg); return TCL_ERROR; } } @@ -1059,7 +1062,7 @@ using namespace sta; else if (stringEq(arg, "data")) $1 = PathClkOrData::data; else { - tclError(interp, "Error: %s not clk or data.", arg); + tclArgError(interp, "%s not clk or data.", arg); return TCL_ERROR; } } @@ -1072,7 +1075,7 @@ using namespace sta; else if (stringEq(arg, "slack")) $1 = sort_by_slack; else { - tclError(interp, "Error: %s not group or slack.", arg); + tclArgError(interp, "%s not group or slack.", arg); return TCL_ERROR; } } @@ -1097,7 +1100,7 @@ using namespace sta; else if (stringEq(arg, "json")) $1 = ReportPathFormat::json; else { - tclError(interp, "Error: unknown path type %s.", arg); + tclArgError(interp, "unknown path type %s.", arg); return TCL_ERROR; } } @@ -1375,7 +1378,7 @@ using namespace sta; else if (stringEq(arg, "none")) $1 = ReducedParasiticType::none; else { - tclError(interp, "Error: %s pi_elmore, pi_pole_residue2, or none.", arg); + tclArgError(interp, "%s pi_elmore, pi_pole_residue2, or none.", arg); return TCL_ERROR; } } @@ -1978,7 +1981,7 @@ redirect_string_end() } void -log_begin(const char *filename) +log_begin_cmd(const char *filename) { Sta::sta()->report()->logBegin(filename); } diff --git a/tcl/Util.tcl b/tcl/Util.tcl index 2dec752a..18a687eb 100644 --- a/tcl/Util.tcl +++ b/tcl/Util.tcl @@ -294,8 +294,13 @@ proc write_stats { filename } { ################################################################ # Begin/end logging all output to a file. +define_cmd_args "log_begin" { filename } + +proc log_begin { filename } { + log_begin_cmd [file nativename $filename] +} + # Defined by StaTcl.i -define_cmd_args "log_begin" {filename} define_cmd_args "log_end" {} # set_debug is NOT in the global namespace diff --git a/test/regression.tcl b/test/regression.tcl index 707db7ea..45b52f26 100755 --- a/test/regression.tcl +++ b/test/regression.tcl @@ -145,9 +145,9 @@ proc run_test { test } { incr errors(error) # For some reason seg faults aren't echoed in the log - add them. - if [file exists $log_file] { + if { [llength $test_errors] > 1 && [file exists $log_file] } { set log_ch [open $log_file "a"] - puts $log_ch "$test_errors" + puts $log_ch $test_errors close $log_ch } diff --git a/util/Debug.cc b/util/Debug.cc index 2d637e34..98fe9aae 100644 --- a/util/Debug.cc +++ b/util/Debug.cc @@ -108,7 +108,7 @@ Debug::print(const char *fmt, { va_list args; va_start(args, fmt); - report_->vprintError(fmt, args); + report_->vprint(fmt, args); va_end(args); } diff --git a/util/Error.cc b/util/Error.cc index ed3f7717..5da427d9 100644 --- a/util/Error.cc +++ b/util/Error.cc @@ -28,6 +28,18 @@ Exception::Exception() : { } +ExceptionMsg::ExceptionMsg(const char *msg) : + Exception(), + msg_(msg) +{ +} + +const char * +ExceptionMsg::what() const noexcept +{ + return msg_.c_str(); +} + ExceptionLine::ExceptionLine(const char *filename, int line) : Exception(), diff --git a/util/Report.cc b/util/Report.cc index f9348df7..932e36bb 100644 --- a/util/Report.cc +++ b/util/Report.cc @@ -42,23 +42,58 @@ Report::~Report() delete [] buffer_; } +void +Report::printToBuffer(const char *fmt, + ...) +{ + va_list args; + va_start(args, fmt); + printToBuffer(fmt, args); + va_end(args); +} + void Report::printToBuffer(const char *fmt, va_list args) +{ + buffer_length_ = 0; + printToBufferAppend(fmt, args); +} + +void +Report::printToBufferAppend(const char *fmt, + ...) +{ + va_list args; + va_start(args, fmt); + printToBufferAppend(fmt, args); + va_end(args); +} + +void +Report::printToBufferAppend(const char *fmt, + va_list args) { // Copy args in case we need to grow the buffer. va_list args_copy; va_copy(args_copy, args); - buffer_length_ = vsnprint(buffer_, buffer_size_, fmt, args); + int length = vsnprint(buffer_ + buffer_length_, buffer_size_, fmt, args); if (buffer_length_ >= buffer_size_) { delete [] buffer_; buffer_size_ = buffer_length_ * 2; buffer_ = new char[buffer_size_]; - buffer_length_ = vsnprint(buffer_, buffer_size_, fmt, args_copy); + length = vsnprint(buffer_ + buffer_length_, buffer_size_, fmt, args_copy); } + buffer_length_ += length; va_end(args_copy); } +void +Report::printBuffer() +{ + printString(buffer_, buffer_length_); +} + size_t Report::printString(const char *buffer, size_t length) @@ -107,86 +142,19 @@ Report::print(const char *fmt, ...) va_end(args); } -size_t -Report::printError(const char *buffer, - size_t length) -{ - size_t ret = length; - if (redirect_to_string_) - redirectStringPrint(buffer, length); - else { - if (redirect_stream_) - ret = min(ret, fwrite(buffer, sizeof(char), length, redirect_stream_)); - else - ret = min(ret, printErrorConsole(buffer, length)); - if (log_stream_) - ret = min(ret, fwrite(buffer, sizeof(char), length, log_stream_)); - } - return ret; -} - -void -Report::vprintError(const char *fmt, - va_list args) -{ - std::unique_lock lock(buffer_lock_); - printToBuffer(fmt, args); - printError(buffer_, buffer_length_); -} - -void -Report::printError(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vprintError(fmt, args); - va_end(args); -} - -void -Report::printDebug(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vprint(fmt, args); - va_end(args); -} - -void -Report::vprintDebug(const char *fmt, - va_list args) -{ - vprint(fmt, args); -} - //////////////////////////////////////////////////////////////// -void -Report::printWarn(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vprintError(fmt, args); - va_end(args); -} - -void -Report::vprintWarn(const char *fmt, - va_list args) -{ - vprintError(fmt, args); -} - void Report::warn(int /* id */, const char *fmt, ...) { - printWarn("Warning: "); va_list args; va_start(args, fmt); - vprintWarn(fmt, args); - printWarn("\n"); + printToBuffer("Warning: "); + printToBufferAppend(fmt, args); + printToBufferAppend("\n"); + printBuffer(); va_end(args); } @@ -197,11 +165,12 @@ Report::fileWarn(int /* id */, const char *fmt, ...) { - printWarn("Warning: %s, line %d ", filename, line); va_list args; va_start(args, fmt); - vprintWarn(fmt, args); - printWarn("\n"); + printToBuffer("Warning: %s, line %d ", filename, line); + printToBufferAppend(fmt, args); + printToBufferAppend("\n"); + printBuffer(); va_end(args); } @@ -212,9 +181,10 @@ Report::vfileWarn(int /* id */, const char *fmt, va_list args) { - printWarn("Warning: %s, line %d ", filename, line); - vprintWarn(fmt, args); - printWarn("\n"); + printToBuffer("Warning: %s, line %d ", filename, line); + printToBufferAppend(fmt, args); + printToBufferAppend("\n"); + printBuffer(); } //////////////////////////////////////////////////////////////// @@ -223,12 +193,13 @@ void Report::error(int /* id */, const char *fmt, ...) { - printError("Error: "); + flush(); va_list args; va_start(args, fmt); - vprintError(fmt, args); - printWarn("\n"); + // No prefix msg, no \n. + printToBuffer(fmt, args); va_end(args); + throw ExceptionMsg(buffer_); } void @@ -238,12 +209,14 @@ Report::fileError(int /* id */, const char *fmt, ...) { - printError("Error: %s, line %d ", filename, line); + flush(); va_list args; va_start(args, fmt); - vprintError(fmt, args); - printWarn("\n"); + // No prefix msg, no \n. + printToBuffer("%s, line %d ", filename, line); + printToBufferAppend(fmt, args); va_end(args); + throw ExceptionMsg(buffer_); } void @@ -251,11 +224,13 @@ Report::vfileError(int /* id */, const char *filename, int line, const char *fmt, - va_list args) + va_list args) { - printError("Error: %s, line %d ", filename, line); - vprintError(fmt, args); - printWarn("\n"); + flush(); + // No prefix msg, no \n. + printToBuffer("%s, line %d ", filename, line); + printToBufferAppend(fmt, args); + throw ExceptionMsg(buffer_); } //////////////////////////////////////////////////////////////// @@ -265,13 +240,13 @@ Report::critical(int /* id */, const char *fmt, ...) { - printError("Critical: "); va_list args; va_start(args, fmt); - vprintError(fmt, args); - printWarn("\n"); + printToBuffer("Critical: "); + printToBufferAppend(fmt, args); + printToBufferAppend("\n"); + printBuffer(); va_end(args); - exit(1); } void @@ -281,11 +256,11 @@ Report::fileCritical(int /* id */, const char *fmt, ...) { - printError("Critical: %s, line %d ", filename, line); va_list args; va_start(args, fmt); - vprintError(fmt, args); - printWarn("\n"); + printToBuffer("Critical: %s, line %d ", filename, line, fmt, args); + printToBufferAppend(fmt, args); + printToBufferAppend("\n"); va_end(args); exit(1); } diff --git a/util/ReportTcl.cc b/util/ReportTcl.cc index 47cb5beb..b7f90cd8 100644 --- a/util/ReportTcl.cc +++ b/util/ReportTcl.cc @@ -277,8 +277,11 @@ Tcl_ChannelType tcl_encap_type_stderr = { //////////////////////////////////////////////////////////////// ReportTcl::ReportTcl() : - Report(), interp_(nullptr), tcl_stdout_(nullptr), tcl_stderr_(nullptr), - tcl_encap_stdout_(nullptr), tcl_encap_stderr_(nullptr) + Report(), interp_(nullptr), + tcl_stdout_(nullptr), + tcl_stderr_(nullptr), + tcl_encap_stdout_(nullptr), + tcl_encap_stderr_(nullptr) { } @@ -318,13 +321,6 @@ ReportTcl::printConsole(const char *buffer, return printTcl(tcl_stdout_, buffer, length); } -size_t -ReportTcl::printErrorConsole(const char *buffer, - size_t length) -{ - return printTcl(tcl_stderr_, buffer, length); -} - size_t ReportTcl::printTcl(Tcl_Channel channel, const char *buffer, @@ -340,69 +336,63 @@ ReportTcl::printTcl(Tcl_Channel channel, &error_code); } +void +ReportTcl::flush() +{ + if (tcl_encap_stdout_) + Tcl_Flush(tcl_encap_stdout_); + if (tcl_encap_stderr_) + Tcl_Flush(tcl_encap_stderr_); +} + // Tcl_Main can eval multiple commands before the flushing the command // output, so the log/redirect commands must force a flush. void ReportTcl::logBegin(const char *filename) { - Tcl_Flush(tcl_encap_stdout_); - Tcl_Flush(tcl_encap_stderr_); + flush(); Report::logBegin(filename); } void ReportTcl::logEnd() { - if (tcl_encap_stdout_) - Tcl_Flush(tcl_encap_stdout_); - if (tcl_encap_stderr_) - Tcl_Flush(tcl_encap_stderr_); + flush(); Report::logEnd(); } void ReportTcl::redirectFileBegin(const char *filename) { - Tcl_Flush(tcl_encap_stdout_); - Tcl_Flush(tcl_encap_stderr_); + flush(); Report::redirectFileBegin(filename); } void ReportTcl::redirectFileAppendBegin(const char *filename) { - Tcl_Flush(tcl_encap_stdout_); - Tcl_Flush(tcl_encap_stderr_); + flush(); Report::redirectFileAppendBegin(filename); } void ReportTcl::redirectFileEnd() { - if (tcl_encap_stdout_) - Tcl_Flush(tcl_encap_stdout_); - if (tcl_encap_stderr_) - Tcl_Flush(tcl_encap_stderr_); + flush(); Report::redirectFileEnd(); } void ReportTcl::redirectStringBegin() { - if (tcl_encap_stdout_) - Tcl_Flush(tcl_encap_stdout_); - if (tcl_encap_stderr_) - Tcl_Flush(tcl_encap_stderr_); + flush(); Report::redirectStringBegin(); } const char * ReportTcl::redirectStringEnd() { - if (tcl_encap_stdout_) - Tcl_Flush(tcl_encap_stdout_); - if (tcl_encap_stderr_) - Tcl_Flush(tcl_encap_stderr_); + flush(); return Report::redirectStringEnd(); }