Add printing summary reports (#4909) (#5018)

This commit is contained in:
Wilson Snyder 2024-03-25 07:03:17 -04:00 committed by GitHub
parent 34e4cffb62
commit 4df9e2e0e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 585 additions and 32 deletions

View File

@ -13,6 +13,7 @@ Verilator 5.023 devel
**Major:**
* Add printing summary reports, use `--quiet` or `+verilator+quiet` to suppress (#4909).
* Support 1800-2023 keywords, and parsing with UNDEFINED warnings.
* Support 1800-2023 preprocessor ifdef expressions.
* Support 1800-2023 DPI headers, svGetTime/svgGetTimeUnit/svGetTimePrecision methods.

View File

@ -58,6 +58,7 @@ if (! GetOptions(
# Switches
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
"quiet!" => \$opt_quiet_exit, # As -quiet implies -quiet-exit
"quiet-exit!" => \$opt_quiet_exit,
"rr!" => \$opt_rr,
"unlimited-stack!" => \$opt_unlimited_stack,
@ -423,7 +424,9 @@ detailed descriptions of these arguments.
--public-params Mark all parameters as public_flat
--public-flat-rw Mark all variables, etc as public_flat_rw
-pvalue+<name>=<value> Overwrite toplevel parameter
--quiet Minimize additional printing
--quiet-exit Don't print the command on failure
--quiet-stats Don't print statistics
--relative-includes Resolve includes relative to current file
--reloop-limit Minimum iterations for forming loops
--report-unoptflat Extra diagnostics for UNOPTFLAT
@ -515,6 +518,7 @@ description of these arguments.
+verilator+prof+exec+start+<value> Set execution profile starting point
+verilator+prof+exec+window+<value> Set execution profile duration
+verilator+prof+vlt+file+<filename> Set PGO profile filename
+verilator+quiet Minimize additional printing
+verilator+rand+reset+<value> Set random reset technique
+verilator+seed+<value> Set random seed
+verilator+V Show verbose version and config

View File

@ -92,6 +92,11 @@ Summary:
profile-guided optimization data runtime filename to dump to. Defaults
to :file:`profile.vlt`.
.. option:: +verilator+quiet
Disable printing the simulation summary report, see :ref:`Simulation
Summary Report`.
.. option:: +verilator+rand+reset+<value>
When a model was Verilated using

View File

@ -1163,11 +1163,20 @@ Summary:
Overwrites the given parameter(s) of the top-level module. See
:vlopt:`-G <-G<name>>` for a detailed description.
.. option:: --quiet
Alias for :vlopt:`--quiet-exit` :vlopt:`--quiet-stats`.
.. option:: --quiet-exit
When exiting due to an error, do not display the "Exiting due to Errors"
nor "Command Failed" messages.
.. option:: --quiet-stats
Disable printing the Verilation statistics report, see :ref:`Verilation
Summary Report`.
.. option:: --relative-includes
When a file references an include file, resolve the filename relative to

View File

@ -12,6 +12,60 @@ Verilated model's executable. For the runtime arguments to a simulated
model, see :ref:`Simulation Runtime Arguments`.
.. _Simulation Summary Report:
Simulation Summary Report
=========================
When simulation finishes, it will print a report to stdout summarizing the
simulation. This requires the model being Verilated with :vlopt:`--main`.
The report may be disabled with :vlopt:`+verilator+quiet`.
For example:
.. code-block::
- S i m u l a t i o n R e p o r t: Verilator ...
- Verilator: End at simtime 123 ns; walltime 1234.001 s; speed 123 ns/s
- Verilator: cpu 22.001 s on 4 threads; alloced 123 MB
The information in this report is:
.. describe:: "Verilator ..."
Program version.
.. describe:: "End at simtime 123 ns"
Verilog $time at which the model finished or stopped.
.. describe:: "walltime 1234.001 s"
Real elapsed wall time in seconds.
.. describe:: "speed 123.1 ns/s"
Simulated time (if non-zero) divided by wall time. e.g. `123 ns/s` means
123 simulated nanoseconds took 1 second of wall time; for a model with
only a 1 GHz clock that would be equivalent to 123.1 cycles per
second. The units are automatically selected to give a number between 1
and 1000. The wall time includes initialization, initial and final
process blocks, so indicates a slower speed than if the model had a
longer runtime.
.. describe:: "cpu 22 s"
CPU time used total across all CPU threads in seconds.
.. describe:: "4 threads"
Number of simultaneous threads used.
.. describe:: "alloced 123 MB"
Total memory used during simulation in megabytes.
.. _Benchmarking & Optimization:
Benchmarking & Optimization

View File

@ -498,3 +498,78 @@ The search paths can be configured by setting some variables:
Sets the installation prefix of an installed SystemC library. (Same as
SYSTEMC_ROOT).
.. _Verilation Summary Report:
Verilation Summary Report
=========================
When Verilator generates code, unless :vlopt:`--quiet-stats` is used, it
will print a report to stdout summarizing the build. For example:
.. code-block::
- V e r i l a t i o n R e p o r t: Verilator ....
- Verilator: Built from 354 MB sources in 247 modules,
into 74 MB in 89 C++ files needing 0.192 MB
- Verilator: Walltime 26.580 s (elab=2.096, cvt=18.268,
bld=2.100); cpu 26.548 s on 1 threads; alloced 2894.672 MB
The information in this report is:
.. describe:: "Verilator ..."
Program version.
.. describe:: "234 MB sources"
Characters of post-preprocessed text in all input
Verilog and Verilator Control files in megabytes.
.. describe:: "247 modules"
Number of interfaces/modules/classes/packages in design before
elaboration.
.. describe:: "into 74 MB"
Characters of output C++ code, including comments in megabytes.
.. describe:: "89 C++ files"
Number of .cpp files created.
.. describe:: "needing 192MB"
Verilation-time minimum-bound estimate of memory needed to run model in
megabytes. (Expect to need significantly more.)
.. describe:: "Walltime 26.580 s"
Real elapsed wall time for Verilation and build.
.. describe:: "elab=2.096"
Wall time to read in files and complete elaboration.
.. describe:: "cvt=18.268"
Wall time for Verilator to process and write output.
.. describe:: "bld=2.1"
Wall time to compile gcc/clang (if using :vlopt:`--build`).
.. describe:: "cpu 22.548 s"
CPU time used, total across all CPU threads.
.. describe:: "4 threads"
Number of simultaneous threads used.
.. describe:: "alloced 123 MB"
Total memory used during build by Verilator executable (excludes
:vlopt:`--build` compiler's usage) in megabytes.

View File

@ -117,6 +117,9 @@ int main(int argc, char** argv) {
contextp->coveragep()->write("logs/coverage.dat");
#endif
// Final simulation summary
contextp->printStatsSummary();
// Return good completion status
// Don't use exit() or destructor won't get called
return 0;

View File

@ -2565,6 +2565,29 @@ std::string VerilatedContext::profVltFilename() const VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
return m_ns.m_profVltFilename;
}
void VerilatedContext::printStatsSummary() VL_MT_UNSAFE {
if (quiet()) return;
VL_PRINTF("- S i m u l a t i o n R e p o r t: %s %s\n", Verilated::productName(),
Verilated::productVersion());
const std::string endwhy = gotError() ? "$stop" : gotFinish() ? "$finish" : "end";
const double simtimeInUnits = VL_TIME_Q() * vl_time_multiplier(timeunit())
* vl_time_multiplier(timeprecision() - timeunit());
const std::string simtime = vl_timescaled_double(simtimeInUnits);
const double walltime = statWallTimeSinceStart();
const double cputime = statCpuTimeSinceStart();
const std::string simtimePerf
= vl_timescaled_double((cputime != 0.0) ? (simtimeInUnits / cputime) : 0, "%0.3f %s");
VL_PRINTF("- Verilator: %s at %s; walltime %0.3f s; speed %s/s\n", endwhy.c_str(),
simtime.c_str(), walltime, simtimePerf.c_str());
const double modelMB = VlOs::memUsageBytes() / 1024.0 / 1024.0;
VL_PRINTF("- Verilator: cpu %0.3f s on %d threads; alloced %0.0f MB\n", cputime,
modelThreads(), modelMB);
}
void VerilatedContext::quiet(bool flag) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_s.m_quiet = flag;
}
void VerilatedContext::randReset(int val) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_s.m_randReset = val;
@ -2632,8 +2655,16 @@ void VerilatedContext::internalsDump() const VL_MT_SAFE {
}
void VerilatedContext::addModel(VerilatedModel* modelp) {
if (!quiet()) {
// CPU time isn't read as starting point until model creation, so that quiet() is set
// Thus if quiet(), avoids slow OS read affecting some usages that make many models
const VerilatedLockGuard lock{m_mutex};
m_ns.m_cpuTimeStart.start();
m_ns.m_wallTimeStart.start();
}
threadPoolp(); // Ensure thread pool is created, so m_threads cannot change any more
m_modelThreads += modelp->threads();
if (VL_UNLIKELY(modelp->threads() > m_threads)) {
std::ostringstream msg;
msg << "VerilatedContext has " << m_threads << " threads but model '"
@ -2762,6 +2793,8 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) {
profExecFilename(str);
} else if (commandArgVlString(arg, "+verilator+prof+vlt+file+", str)) {
profVltFilename(str);
} else if (arg == "+verilator+quiet") {
quiet(true);
} else if (commandArgVlUint64(arg, "+verilator+rand+reset+", u64, 0, 2)) {
randReset(static_cast<int>(u64));
} else if (commandArgVlUint64(arg, "+verilator+seed+", u64, 1,
@ -2839,6 +2872,18 @@ uint64_t VerilatedContextImp::randSeedDefault64() const VL_MT_SAFE {
}
}
//======================================================================
// VerilatedContext:: Statistics
double VerilatedContext::statCpuTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex};
return m_ns.m_cpuTimeStart.deltaTime();
}
double VerilatedContext::statWallTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex) {
const VerilatedLockGuard lock{m_mutex};
return m_ns.m_wallTimeStart.deltaTime();
}
//======================================================================
// VerilatedContext:: Methods - scopes
@ -3321,3 +3366,7 @@ void VlDeleter::deleteAll() VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_deleteMutex) VL_M
}
//===========================================================================
// OS functions (last, so we have minimal OS dependencies above)
#define VL_ALLOW_VERILATEDOS_C
#include "verilatedos_c.h"

View File

@ -354,13 +354,14 @@ protected:
struct Serialized final { // All these members serialized/deserialized
// No std::strings or pointers or will serialize badly!
// Fast path
uint64_t m_time = 0; // Current $time (unscaled), 0=at zero, or legacy
bool m_assertOn = true; // Assertions are enabled
bool m_calcUnusedSigs = false; // Waves file on, need all signals calculated
bool m_fatalOnError = true; // Fatal on $stop/non-fatal error
bool m_fatalOnVpiError = true; // Fatal on vpi error/unsupported
bool m_gotError = false; // A $finish statement executed
bool m_gotFinish = false; // A $finish or $stop statement executed
uint64_t m_time = 0; // Current $time (unscaled), 0=at zero, or legacy
bool m_quiet = false; // Quiet, no summary report
// Slow path
int8_t m_timeunit; // Time unit as 0..15
int8_t m_timeprecision; // Time precision as 0..15
@ -390,6 +391,8 @@ protected:
std::string m_coverageFilename; // +coverage+file filename
std::string m_profExecFilename; // +prof+exec+file filename
std::string m_profVltFilename; // +prof+vlt filename
VlOs::DeltaCpuTime m_cpuTimeStart{false}; // CPU time, starts when create first model
VlOs::DeltaWallTime m_wallTimeStart{false}; // Wall time, starts when create first model
} m_ns;
mutable VerilatedMutex m_argMutex; // Protect m_argVec, m_argVecLoaded
@ -405,6 +408,8 @@ protected:
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
// Number of threads to use for simulation (size of m_threadPool + 1 for main thread)
unsigned m_threads = std::thread::hardware_concurrency();
// Number of threads in added models
unsigned m_modelThreads = 0;
// The thread pool shared by all models added to this context
std::unique_ptr<VerilatedVirtualBase> m_threadPool;
// The execution profiler shared by all models added to this context
@ -489,6 +494,12 @@ public:
void gotFinish(bool flag) VL_MT_SAFE;
/// Return if got a $finish or $stop/error
bool gotFinish() const VL_MT_SAFE { return m_s.m_gotFinish; }
/// Print statistics summary (if not quiet)
void printStatsSummary() VL_MT_UNSAFE;
/// Enable quiet (also prevents need for OS calls to get CPU time)
void quiet(bool flag) VL_MT_SAFE;
/// Return if quiet enabled
bool quiet() const VL_MT_SAFE { return m_s.m_quiet; }
/// Select initial value of otherwise uninitialized signals.
/// 0 = Set to zeros
/// 1 = Set all bits to one
@ -501,6 +512,11 @@ public:
/// Set default random seed, 0 = seed it automatically
int randSeed() const VL_MT_SAFE { return m_s.m_randSeed; }
/// Return statistic: CPU time delta from model created until now
double statCpuTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex);
/// Return statistic: Wall time delta from model created until now
double statWallTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex);
// Time handling
/// Returns current simulation time in units of timeprecision().
///
@ -544,6 +560,8 @@ public:
/// Get number of threads used for simulation (including the main thread)
unsigned threads() const { return m_threads; }
/// Get number of threads in added models (for statistical use only)
unsigned modelThreads() const { return m_modelThreads; }
/// Set number of threads used for simulation (including the main thread)
/// Can only be called before the thread pool is created (before first model is added).
void threads(unsigned n);

View File

@ -343,6 +343,7 @@ extern "C" void __gcov_dump();
#include <cstdint>
#include <cinttypes>
#include <cmath>
#include <ctime>
#ifndef VL_NO_LEGACY
using vluint8_t = uint8_t; ///< 8-bit unsigned type (backward compatibility)
@ -610,6 +611,45 @@ static inline double VL_ROUND(double n) {
#define VL_OFFSETOF(type, field) \
(reinterpret_cast<size_t>(&(reinterpret_cast<type*>(0x10000000)->field)) - 0x10000000)
//=========================================================================
// Time and performance
namespace VlOs {
extern uint64_t memUsageBytes(); ///< Return memory usage in bytes, or 0 if not implemented
// Internal: Record CPU time, starting point on construction, and current delta from that
class DeltaCpuTime final {
double m_start{}; // Time constructed at
static double gettime();
public:
// Construct, and if startit is true, start() timer
explicit DeltaCpuTime(bool startit) {
if (startit) start();
}
void start() { m_start = gettime(); } // Start timer; record current time
double deltaTime() const { // Return time between now and start()
return (m_start == 0.0) ? 0.0 : gettime() - m_start;
}
};
// Internal: Record wall time, starting point on construction, and current delta from that
class DeltaWallTime final {
double m_start{}; // Time constructed at
static double gettime();
public:
// Construct, and if startit is true, start() timer
explicit DeltaWallTime(bool startit) {
if (startit) start();
}
void start() { m_start = gettime(); } // Start timer; record current time
double deltaTime() const { // Return time between now and start()
return (m_start == 0.0) ? 0.0 : gettime() - m_start;
}
};
} //namespace VlOs
//=========================================================================
// Conversions

101
include/verilatedos_c.h Normal file
View File

@ -0,0 +1,101 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Code available from: https://verilator.org
//
// Copyright 2003-2024 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
///
/// \file
/// \brief Verilated/Verilator common implementation for OS portability
///
/// This is compiled as part of other .cpp files to reduce compile time
/// and as such is a .h file rather than .cpp file.
///
//*************************************************************************
#ifndef VL_ALLOW_VERILATEDOS_C
#error "This file should be included only from V3Os.cpp/Verilated.cpp"
#endif
#include "verilatedos.h"
// clang-format off
#if defined(_WIN32) || defined(__MINGW32__)
# include <windows.h> // LONG for bcrypt.h on MINGW
# include <processthreadsapi.h> // GetProcessTimes
# include <psapi.h> // GetProcessMemoryInfo
#endif
// clang-format on
namespace VlOs {
//=========================================================================
// VlOs::VlGetCpuTime/VlGetWallTime implementation
double DeltaCpuTime::gettime() {
#if defined(_WIN32) || defined(__MINGW32__)
FILETIME lpCreationTime, lpExitTime, lpKernelTime, lpUserTime;
if (0
!= GetProcessTimes(GetCurrentProcess(), &lpCreationTime, &lpExitTime, &lpKernelTime,
&lpUserTime)) {
return static_cast<double>(static_cast<uint64_t>(lpUserTime.dwLowDateTime)
| static_cast<uint64_t>(lpUserTime.dwHighDateTime) << 32ULL)
* 1e-7;
}
#else
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
timespec ts;
if (0 != clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) return ts.tv_sec + ts.tv_nsec * 1e-9;
#endif
return 0.0;
}
double DeltaWallTime::gettime() {
#if defined(_WIN32) || defined(__MINGW32__)
FILETIME ft; // contains number of 0.1us intervals since the beginning of 1601 UTC.
GetSystemTimeAsFileTime(&ft);
const uint64_t tenthus
= ((static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime + 5ULL);
return static_cast<double>(tenthus) * 1e-7;
#else
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
timespec ts;
if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) return ts.tv_sec + ts.tv_nsec * 1e-9;
return 0.0;
#endif
}
//=========================================================================
// VlOs::memUsageBytes implementation
uint64_t memUsageBytes() {
#if defined(_WIN32) || defined(__MINGW32__)
const HANDLE process = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc))) {
// The best we can do using simple Windows APIs is to get the size of the working set.
return pmc.WorkingSetSize;
}
return 0;
#else
// Highly unportable. Sorry
const char* const statmFilename = "/proc/self/statm";
FILE* const fp = fopen(statmFilename, "r");
if (!fp) return 0;
uint64_t size, resident, share, text, lib, data, dt; // All in pages
const int items = fscanf(
fp, "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64,
&size, &resident, &share, &text, &lib, &data, &dt);
fclose(fp);
if (VL_UNCOVERABLE(7 != items)) return 0;
return (text + data) * getpagesize();
#endif
}
//=========================================================================
} //namespace VlOs

View File

@ -110,6 +110,10 @@ private:
puts("\n");
}
puts("// Print statistical summary report\n");
puts("contextp->printStatsSummary();\n");
puts("\n");
puts("return 0;\n");
puts("}\n");

View File

@ -1415,7 +1415,12 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
m_public_params = flag;
v3Global.dpi(true);
});
DECL_OPTION("-quiet", CbOnOff, [this](bool flag) {
m_quietExit = flag;
m_quietStats = flag;
});
DECL_OPTION("-quiet-exit", OnOff, &m_quietExit);
DECL_OPTION("-quiet-stats", OnOff, &m_quietStats);
DECL_OPTION("-relative-includes", OnOff, &m_relativeIncludes);
DECL_OPTION("-reloop-limit", CbVal, [this, fl](const char* valp) {

View File

@ -271,8 +271,9 @@ private:
bool m_publicFlatRW = false; // main switch: --public-flat-rw
bool m_public_params = false; // main switch: --public-params
bool m_quietExit = false; // main switch: --quiet-exit
bool m_relativeIncludes = false; // main switch: --relative-includes
bool m_reportUnoptflat = false; // main switch: --report-unoptflat
bool m_quietStats = false; // main switch: --quiet-stats
bool m_relativeIncludes = false; // main switch: --relative-includes
bool m_reportUnoptflat = false; // main switch: --report-unoptflat
bool m_savable = false; // main switch: --savable
bool m_std = true; // main switch: --std
bool m_structsPacked = false; // main switch: --structs-packed
@ -524,6 +525,7 @@ public:
bool lintOnly() const VL_MT_SAFE { return m_lintOnly; }
bool ignc() const { return m_ignc; }
bool quietExit() const VL_MT_SAFE { return m_quietExit; }
bool quietStats() const VL_MT_SAFE { return m_quietStats; }
bool reportUnoptflat() const { return m_reportUnoptflat; }
bool verilate() const { return m_verilate; }
bool vpi() const { return m_vpi; }

View File

@ -61,7 +61,6 @@ VL_DEFINE_DEBUG_FUNCTIONS;
# include <chrono>
# include <direct.h> // mkdir
# include <io.h> // open, read, write, close
# include <psapi.h> // GetProcessMemoryInfo
# include <thread>
// These macros taken from gdbsupport/gdb_wait.h in binutils-gdb
# ifndef WIFEXITED
@ -80,6 +79,9 @@ VL_DEFINE_DEBUG_FUNCTIONS;
#endif
// clang-format on
#define VL_ALLOW_VERILATEDOS_C
#include "verilatedos_c.h"
//######################################################################
// Environment
@ -397,7 +399,7 @@ uint64_t V3Os::timeUsecs() {
FILETIME ft; // contains number of 0.1us intervals since the beginning of 1601 UTC.
GetSystemTimeAsFileTime(&ft);
uint64_t us
const uint64_t us
= ((static_cast<uint64_t>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime + 5ULL) / 10ULL;
return us - EPOCH_DIFFERENCE_USECS;
#else
@ -408,30 +410,6 @@ uint64_t V3Os::timeUsecs() {
#endif
}
uint64_t V3Os::memUsageBytes() {
#if defined(_WIN32) || defined(__MINGW32__)
const HANDLE process = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(process, &pmc, sizeof(pmc))) {
// The best we can do using simple Windows APIs is to get the size of the working set.
return pmc.WorkingSetSize;
}
return 0;
#else
// Highly unportable. Sorry
const char* const statmFilename = "/proc/self/statm";
FILE* const fp = fopen(statmFilename, "r");
if (!fp) return 0;
uint64_t size, resident, share, text, lib, data, dt; // All in pages
const int items = fscanf(
fp, "%" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64,
&size, &resident, &share, &text, &lib, &data, &dt);
fclose(fp);
if (VL_UNCOVERABLE(7 != items)) return 0;
return (text + data) * getpagesize();
#endif
}
void V3Os::u_sleep(int64_t usec) {
#if defined(_WIN32) || defined(__MINGW32__)
std::this_thread::sleep_for(std::chrono::microseconds(usec));

View File

@ -71,11 +71,10 @@ public:
static uint64_t rand64(std::array<uint64_t, 2>& stater);
static string trueRandom(size_t size) VL_MT_SAFE;
// METHODS (time & performance)
// METHODS (time & performance) (See also VlOs methods)
static void u_sleep(int64_t usec); ///< Sleep for a given number of microseconds.
/// Return wall time since epoch in microseconds, or 0 if not implemented
static uint64_t timeUsecs();
static uint64_t memUsageBytes(); ///< Return memory usage in bytes, or 0 if not implemented
// METHODS (sub command)
/// Run system command, returns the exit code of the child process.

View File

@ -109,9 +109,14 @@ public:
// Symbolic names for some statistics that are later read by summaryReport()
static constexpr const char* STAT_CPP_CHARS = "Output, C++ bytes written";
static constexpr const char* STAT_CPP_FILES = "Output, C++ files written";
static constexpr const char* STAT_CPUTIME = "CPU time, Total (sec)";
static constexpr const char* STAT_MODEL_SIZE = "Size prediction, Model total (bytes)";
static constexpr const char* STAT_SOURCE_CHARS = "Input, Verilog bytes read";
static constexpr const char* STAT_SOURCE_MODULES = "Input, Verilog modules read";
static constexpr const char* STAT_WALLTIME = "Wall time, Total (sec)";
static constexpr const char* STAT_WALLTIME_BUILD = "Wall time, Build (sec)";
static constexpr const char* STAT_WALLTIME_CVT = "Wall time, Conversion (sec)";
static constexpr const char* STAT_WALLTIME_ELAB = "Wall time, Elaboration (sec)";
static void addStat(const V3Statistic&);
static void addStat(const string& stage, const string& name, double value,
@ -126,6 +131,11 @@ public:
static void addStatPerf(const string& name, double value) {
addStat(V3Statistic{"*", name, value, 6, true, true});
}
/// Return value of statistic, or zero if not found
static double getStatSum(const string& name);
static uint64_t getStatSumQ(const string& name) {
return static_cast<uint64_t>(getStatSum(name));
}
/// Called each stage
static void statsStage(const string& name);
/// Called by the top level to collect statistics
@ -135,6 +145,8 @@ public:
static void statsReport();
/// Called by debug dumps
static void infoHeader(std::ofstream& os, const string& prefix);
/// Called for final build report
static void summaryReport();
};
#endif // Guard

View File

@ -162,6 +162,17 @@ public:
// METHODS
static void addStat(const V3Statistic& stat) { s_allStats.push_back(stat); }
static double getStatSum(const string& name) {
// O(n^2) if called a lot; present assumption is only a small call count
for (auto& itr : s_allStats) {
const V3Statistic* const repp = &itr;
if (repp->name() == name) return repp->value();
}
return 0.0;
}
static void calculate() { sumit(); }
// CONSTRUCTORS
explicit StatsReport(std::ofstream* aofp)
: os(*aofp) { // Need () or GCC 4.8 false warning
@ -189,6 +200,8 @@ void V3Statistic::dump(std::ofstream& os) const {
void V3Stats::addStat(const V3Statistic& stat) { StatsReport::addStat(stat); }
double V3Stats::getStatSum(const string& name) { return StatsReport::getStatSum(name); }
void V3Stats::statsStage(const string& name) {
static double lastWallTime = -1;
static int fileNumber = 0;
@ -202,7 +215,7 @@ void V3Stats::statsStage(const string& name) {
V3Stats::addStatPerf("Stage, Elapsed time (sec), " + digitName, wallTimeDelta);
V3Stats::addStatPerf("Stage, Elapsed time (sec), TOTAL", wallTimeDelta);
const double memory = V3Os::memUsageBytes() / 1024.0 / 1024.0;
const double memory = VlOs::memUsageBytes() / 1024.0 / 1024.0;
V3Stats::addStatPerf("Stage, Memory (MB), " + digitName, memory);
}
@ -229,3 +242,31 @@ void V3Stats::statsReport() {
ofp->close();
VL_DO_DANGLING(delete ofp, ofp);
}
void V3Stats::summaryReport() {
StatsReport::calculate();
std::cout << "- V e r i l a t i o n R e p o r t: " << V3Options::version() << "\n";
std::cout << std::setprecision(3) << std::fixed;
const double sourceCharsMB = V3Stats::getStatSumQ(STAT_SOURCE_CHARS) / 1024.0 / 1024.0;
const double cppCharsMB = V3Stats::getStatSumQ(STAT_CPP_CHARS) / 1024.0 / 1024.0;
const uint64_t sourceModules = V3Stats::getStatSumQ(STAT_SOURCE_MODULES);
const uint64_t cppFiles = V3Stats::getStatSumQ(STAT_CPP_FILES);
const double modelMB = V3Stats::getStatSum(STAT_MODEL_SIZE) / 1024.0 / 1024.0;
std::cout << "- Verilator: Built from " << sourceCharsMB << " MB sources in " << sourceModules
<< " modules, into " << cppCharsMB << " MB in " << cppFiles << " C++ files needing "
<< modelMB << " MB\n";
const double walltime = V3Stats::getStatSum(STAT_WALLTIME);
const double walltimeElab = V3Stats::getStatSum(STAT_WALLTIME_ELAB);
const double walltimeCvt = V3Stats::getStatSum(STAT_WALLTIME_CVT);
const double walltimeBuild = V3Stats::getStatSum(STAT_WALLTIME_BUILD);
const double cputime = V3Stats::getStatSum(STAT_CPUTIME);
std::cout << "- Verilator: Walltime " << walltime << " s (elab=" << walltimeElab
<< ", cvt=" << walltimeCvt << ", bld=" << walltimeBuild << "); cpu " << cputime
<< " s on " << std::max(v3Global.opt.verilateJobs(), v3Global.opt.buildJobs())
<< " threads";
const double memory = VlOs::memUsageBytes() / 1024.0 / 1024.0;
if (VL_UNCOVERABLE(memory != 0.0)) std::cout << "; alloced " << memory << " MB";
std::cout << "\n";
}

View File

@ -136,6 +136,8 @@ static void emitXmlOrJson() VL_MT_DISABLED {
static void process() {
{
const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()};
VlOs::DeltaWallTime elabWallTime{true};
// Sort modules by level so later algorithms don't need to care
V3LinkLevel::modSortByLevel();
V3Error::abortIfErrors();
@ -209,6 +211,10 @@ static void process() {
v3Global.assertDTypesResolved(true);
v3Global.widthMinUsage(VWidthMinUsage::MATCHES_WIDTH);
// End of elaboration
V3Stats::addStatPerf(V3Stats::STAT_WALLTIME_ELAB, elabWallTime.deltaTime());
VlOs::DeltaWallTime cvtWallTime{true};
// Coverage insertion
// Before we do dead code elimination and inlining, or we'll lose it.
if (v3Global.opt.coverage()) V3Coverage::coverage(v3Global.rootp());
@ -582,6 +588,9 @@ static void process() {
} else if (v3Global.opt.dpiHdrOnly()) {
V3EmitC::emitcSyms(true);
}
// End of conversion
V3Stats::addStatPerf(V3Stats::STAT_WALLTIME_CVT, cvtWallTime.deltaTime());
}
if (!v3Global.opt.serializeOnly()
&& !v3Global.opt.dpiHdrOnly()) { // Unfortunately we have some lint checks in emitcImp.
@ -778,11 +787,14 @@ static void execBuildJob() {
UASSERT(v3Global.opt.build(), "--build is not specified.");
UASSERT(v3Global.opt.gmake(), "--build requires GNU Make.");
UASSERT(!v3Global.opt.cmake(), "--build cannot use CMake.");
VlOs::DeltaWallTime buildWallTime{true};
UINFO(1, "Start Build\n");
const string cmdStr = buildMakeCmd(v3Global.opt.prefix() + ".mk", "");
V3Os::filesystemFlushBuildDir(v3Global.opt.hierTopDataDir());
const int exit_code = V3Os::system(cmdStr);
V3Stats::addStatPerf(V3Stats::STAT_WALLTIME_BUILD, buildWallTime.deltaTime());
if (exit_code != 0) {
v3error(cmdStr << " exited with " << exit_code << std::endl);
std::exit(exit_code);
@ -807,6 +819,8 @@ static void execHierVerilation() {
int main(int argc, char** argv) {
// General initialization
std::ios::sync_with_stdio();
VlOs::DeltaWallTime wallTimeTotal{true};
VlOs::DeltaCpuTime cpuTimeTotal{true};
time_t randseed;
time(&randseed);
@ -855,5 +869,11 @@ int main(int argc, char** argv) {
FileLine::deleteAllRemaining();
}
if (!v3Global.opt.quietStats() && !v3Global.opt.preprocOnly()) {
V3Stats::addStatPerf(V3Stats::STAT_CPUTIME, cpuTimeTotal.deltaTime());
V3Stats::addStatPerf(V3Stats::STAT_WALLTIME, wallTimeTotal.deltaTime());
V3Stats::summaryReport();
}
UINFO(1, "Done, Exiting...\n");
}

View File

@ -0,0 +1,22 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1);
compile(
verilator_flags2 => ['--quiet-stats'],
verilator_make_gcc => 0,
logfile => $Self->{run_log_filename},
);
file_grep_not($Self->{obj_dir}.'/vlt_compile.log', qr/V e r i l a t/i,);
ok(1);
1;

View File

@ -0,0 +1,12 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2008 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
module t (/*AUTOARG*/);
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,24 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1);
top_filename("t/t_flag_quiet_stats.v");
compile(
verilator_flags2 => ['--quiet'],
verilator_make_gcc => 0,
logfile => $Self->{run_log_filename},
);
file_grep_not($Self->{obj_dir}.'/vlt_compile.log', qr/V e r i l a t/i,);
ok(1);
1;

View File

@ -0,0 +1,24 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1);
top_filename("t/t_flag_quiet_stats.v");
compile(
verilator_flags2 => ['--quiet --no-quiet-stats'],
verilator_make_gcc => 0,
logfile => $Self->{run_log_filename},
);
file_grep($Self->{obj_dir}.'/vlt_compile.log', qr/V e r i l a t/i,);
ok(1);
1;

View File

@ -0,0 +1,35 @@
#!/usr/bin/env perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt_all => 1);
compile(
verilator_flags2 => ["--binary --quiet"],
);
execute(
all_run_flags => ["+verilator+quiet"],
logfile => "$Self->{obj_dir}/sim__quiet.log",
);
file_grep_not("$Self->{obj_dir}/sim__quiet.log", qr/S i m u l a t/i,);
#---
execute(
all_run_flags => [""],
logfile => "$Self->{obj_dir}/sim__noquiet.log",
);
file_grep("$Self->{obj_dir}/sim__noquiet.log", qr/S i m u l a t/i,);
ok(1);
1;

View File

@ -0,0 +1,16 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2019 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
timeunit 1us;
timeprecision 1ns;
module t;
initial begin
#10;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule