From a481ae0f23a89a7446e8fd7c5600b0ca1307cfbb Mon Sep 17 00:00:00 2001 From: ALIEN Date: Tue, 25 Oct 2016 09:44:37 +0200 Subject: [PATCH] Renamed missing log folder to logging --- MAGE/MAGE.vcxproj | 16 +-- MAGE/MAGE.vcxproj.filters | 60 ++++----- MAGE/MAGE/src/core/engine.hpp | 2 +- MAGE/MAGE/src/logging/debug.hpp | 24 ++++ MAGE/MAGE/src/logging/error.cpp | 148 +++++++++++++++++++++ MAGE/MAGE/src/logging/error.hpp | 50 +++++++ MAGE/MAGE/src/logging/logging.hpp | 40 ++++++ MAGE/MAGE/src/logging/progressreporter.cpp | 141 ++++++++++++++++++++ MAGE/MAGE/src/logging/progressreporter.hpp | 94 +++++++++++++ MAGE/MAGE/src/logging/timer.cpp | 65 +++++++++ MAGE/MAGE/src/logging/timer.hpp | 96 +++++++++++++ 11 files changed, 697 insertions(+), 39 deletions(-) create mode 100644 MAGE/MAGE/src/logging/debug.hpp create mode 100644 MAGE/MAGE/src/logging/error.cpp create mode 100644 MAGE/MAGE/src/logging/error.hpp create mode 100644 MAGE/MAGE/src/logging/logging.hpp create mode 100644 MAGE/MAGE/src/logging/progressreporter.cpp create mode 100644 MAGE/MAGE/src/logging/progressreporter.hpp create mode 100644 MAGE/MAGE/src/logging/timer.cpp create mode 100644 MAGE/MAGE/src/logging/timer.hpp diff --git a/MAGE/MAGE.vcxproj b/MAGE/MAGE.vcxproj index 50c385169..fd2c99d7d 100644 --- a/MAGE/MAGE.vcxproj +++ b/MAGE/MAGE.vcxproj @@ -26,11 +26,11 @@ - - - - - + + + + + @@ -52,9 +52,9 @@ - - - + + + diff --git a/MAGE/MAGE.vcxproj.filters b/MAGE/MAGE.vcxproj.filters index 5da556bc5..93501d4ba 100644 --- a/MAGE/MAGE.vcxproj.filters +++ b/MAGE/MAGE.vcxproj.filters @@ -49,12 +49,6 @@ {23b667d5-379d-444b-8454-b21d92f99a67} - - {c7374162-a25a-4c28-8475-0b93646cf99c} - - - {dbb452e9-4d9e-4ce3-9101-98b8782a0759} - {8463f1af-bd9e-4155-89f6-bb804a124c73} @@ -73,6 +67,12 @@ {69b1cee0-5512-4d9b-ab9a-f0dbb346243b} + + {dbb452e9-4d9e-4ce3-9101-98b8782a0759} + + + {c7374162-a25a-4c28-8475-0b93646cf99c} + @@ -87,21 +87,6 @@ Header Files\core - - Header Files\log - - - Header Files\log - - - Header Files\log - - - Header Files\log - - - Header Files\log - Header Files\math @@ -162,20 +147,26 @@ Header Files\scripting + + Header Files\logging + + + Header Files\logging + + + Header Files\logging + + + Header Files\logging + + + Header Files\logging + Source Files\core - - Source Files\log - - - Source Files\log - - - Source Files\log - Source Files\parallel @@ -194,5 +185,14 @@ Source Files\scripting + + Source Files\logging + + + Source Files\logging + + + Source Files\logging + \ No newline at end of file diff --git a/MAGE/MAGE/src/core/engine.hpp b/MAGE/MAGE/src/core/engine.hpp index 175ba7fb0..7d39ac1be 100644 --- a/MAGE/MAGE/src/core/engine.hpp +++ b/MAGE/MAGE/src/core/engine.hpp @@ -101,7 +101,7 @@ namespace mage { #include "collection\collection.hpp" #include "math\math.hpp" #include "parallel\parallel.hpp" -#include "log\log.hpp" +#include "logging\logging.hpp" #include "memory\memory.hpp" #include "resource\resource.hpp" #include "state\state.hpp" diff --git a/MAGE/MAGE/src/logging/debug.hpp b/MAGE/MAGE/src/logging/debug.hpp new file mode 100644 index 000000000..177544881 --- /dev/null +++ b/MAGE/MAGE/src/logging/debug.hpp @@ -0,0 +1,24 @@ +#pragma once + +//----------------------------------------------------------------------------- +// System Includes +//----------------------------------------------------------------------------- +#pragma region + +#include + +#pragma endregion + +//----------------------------------------------------------------------------- +// Engine Defines +//----------------------------------------------------------------------------- +#pragma region + +#ifdef NDEBUG +#define Assert(expr) (__noop) +#else +#define Assert(expr) ((expr) ? __noop : Severe("Assertion \"%s\" failed in %s, line %d", \ + #expr, __FILE__, __LINE__)) +#endif + +#pragma endregion \ No newline at end of file diff --git a/MAGE/MAGE/src/logging/error.cpp b/MAGE/MAGE/src/logging/error.cpp new file mode 100644 index 000000000..2d52fa331 --- /dev/null +++ b/MAGE/MAGE/src/logging/error.cpp @@ -0,0 +1,148 @@ +//----------------------------------------------------------------------------- +// System Includes +//----------------------------------------------------------------------------- +#pragma region + +#include + +#pragma endregion + +//----------------------------------------------------------------------------- +// Engine Includes +//----------------------------------------------------------------------------- +#pragma region + +#include "engine.hpp" + +#pragma endregion + +//----------------------------------------------------------------------------- +// Engine Declarations and Definitions +//----------------------------------------------------------------------------- +namespace mage { + + /** + Finds the end of a word. + + @param[in] buffer + Pointer to the first character. + @return Pointer to the end of the word. + This means the pointer points to a space + or null-terminating character. + */ + const char *FindWordEnd(const char *buffer) { + while (*buffer != '\0' && !isspace(*buffer)) { + ++buffer; + } + return buffer; + } + + /** + Process the given error. + + @param[in] format + The format of the error string. + @param[in] args + The arguments of the format string. + @param[in] error_type + The type of the error. + @param[in] error_disposition + Disposition of the error. + */ + void ProcessError(const char *format, const va_list args, + const string &error_type, int error_disposition) { + + if (error_disposition == MAGE_ERROR_IGNORE) { + // MAGE_ERROR_IGNORE + return; + } + + // MAGE_ERROR_CONTINUE and MAGE_ERROR_ABORT + // Print formatted error message + const int width = max(20, TerminalWidth() - 2); + string error_string = error_type + ": "; + size_t error_pos = error_string.size(); + + char error_buffer[2048]; + // Write formatted output using a pointer to a list of arguments. + vsnprintf_s(error_buffer, sizeof(error_buffer), _TRUNCATE, format, args); + + const char *msg_pos = error_buffer; + while (true) { + while (*msg_pos != '\0' && isspace(*msg_pos)) { + ++msg_pos; + } + if (*msg_pos == '\0') { + break; + } + + // isspace(*msg_pos) == true + + const char *word_end = FindWordEnd(msg_pos); + if (error_pos + word_end - msg_pos > width) { + error_string += "\n "; + error_pos = 4; + } + while (msg_pos != word_end) { + error_string += *msg_pos; + ++msg_pos; + ++error_pos; + } + error_string += ' '; + ++error_pos; + } + + // Writes the error_string pointed by format to stderr. + fprintf(stderr, "%s\n", error_string.c_str()); + + if (error_disposition == MAGE_ERROR_ABORT) { + // MAGE_ERROR_ABORT + __debugbreak(); + } + } + + void Info(const char *format, ...) { + if (!general_configuration.IsVerbose() || general_configuration.IsQuiet()) { + // Do not process info in non-verbose mode. + // Do not process info in quiet mode. + return; + } + va_list args; + // Retrieve the additional arguments after format + va_start(args, format); + ProcessError(format, args, "Notice", MAGE_ERROR_CONTINUE); + // End using variable argument list + va_end(args); + } + + void Warning(const char *format, ...) { + if (general_configuration.IsQuiet()) { + // Do not process warning in quiet mode. + return; + } + va_list args; + // Retrieve the additional arguments after format + va_start(args, format); + ProcessError(format, args, "Warning", MAGE_ERROR_CONTINUE); + // End using variable argument list + va_end(args); + } + + void Error(const char *format, ...) { + va_list args; + // Retrieve the additional arguments after format + va_start(args, format); + ProcessError(format, args, "Error", MAGE_ERROR_CONTINUE); + // End using variable argument list + va_end(args); + } + + void Severe(const char *format, ...) { + va_list args; + // Retrieve the additional arguments after format + va_start(args, format); + ProcessError(format, args, "Fatal Error", MAGE_ERROR_ABORT); + // End using variable argument list + va_end(args); + } +} \ No newline at end of file diff --git a/MAGE/MAGE/src/logging/error.hpp b/MAGE/MAGE/src/logging/error.hpp new file mode 100644 index 000000000..03537e65a --- /dev/null +++ b/MAGE/MAGE/src/logging/error.hpp @@ -0,0 +1,50 @@ +#pragma once + +//----------------------------------------------------------------------------- +// Engine Defines +//----------------------------------------------------------------------------- +#pragma region + +#define MAGE_ERROR_IGNORE 0 +#define MAGE_ERROR_CONTINUE 1 +#define MAGE_ERROR_ABORT 2 + +#pragma endregion + +//----------------------------------------------------------------------------- +// Engine Declarations and Definitions +//----------------------------------------------------------------------------- +namespace mage { + + /** + Notifies an info message. + + @param[in] format + Pointer to the message format. + */ + void Info(const char *format, ...); + + /** + Notifies a warning message. + + @param[in] format + Pointer to the message format. + */ + void Warning(const char *format, ...); + + /** + Notifies an error message. + + @param[in] format + Pointer to the message format. + */ + void Error(const char *format, ...); + + /** + Notifies a severe message. + + @param[in] format + Pointer to the message format. + */ + void Severe(const char *format, ...); +} \ No newline at end of file diff --git a/MAGE/MAGE/src/logging/logging.hpp b/MAGE/MAGE/src/logging/logging.hpp new file mode 100644 index 000000000..af18e9ae3 --- /dev/null +++ b/MAGE/MAGE/src/logging/logging.hpp @@ -0,0 +1,40 @@ +#pragma once + +//----------------------------------------------------------------------------- +// Engine Declarations and Definitions +//----------------------------------------------------------------------------- +namespace mage { + + /** + Returns the fixed terminal width. + + @return The fixed terminal width. + */ + inline int TerminalWidth() { + // Retrieve a handle to the standard output device. + const HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + if (h == INVALID_HANDLE_VALUE || h == NULL) { + // Print error message if the handle is invalid. + fprintf(stderr, "GetStdHandle() call failed"); + return 80; + } + // Structure containing information about a console screen buffer. + CONSOLE_SCREEN_BUFFER_INFO buffer_info = { 0 }; + GetConsoleScreenBufferInfo(h, &buffer_info); + // dwSize: a COORD structure that contains the size of the console + // screen buffer in character columns and rows. + return buffer_info.dwSize.X; + } +} + +//----------------------------------------------------------------------------- +// Engine Includes +//----------------------------------------------------------------------------- +#pragma region + +#include "logging\timer.hpp" +#include "logging\progressreporter.hpp" +#include "logging\error.hpp" +#include "logging\debug.hpp" + +#pragma endregion \ No newline at end of file diff --git a/MAGE/MAGE/src/logging/progressreporter.cpp b/MAGE/MAGE/src/logging/progressreporter.cpp new file mode 100644 index 000000000..dff0b7381 --- /dev/null +++ b/MAGE/MAGE/src/logging/progressreporter.cpp @@ -0,0 +1,141 @@ +//----------------------------------------------------------------------------- +// Engine Includes +//----------------------------------------------------------------------------- +#pragma region + +#include "engine.hpp" + +#pragma endregion + +//----------------------------------------------------------------------------- +// Engine Definitions +//----------------------------------------------------------------------------- +namespace mage { + + ProgressReporter::ProgressReporter(uint32_t nb_work, const string &title, uint32_t bar_length) + : m_nb_work_total(nb_work), m_nb_work_done(0), m_nb_plusses_printed(0) { + + if (bar_length == 0) { + bar_length = TerminalWidth() - 28; + } + + m_mutex = Mutex::Create(); + + m_nb_plusses_total = max(2, bar_length - (uint32_t)title.size()); + + m_timer = new Timer(); + m_timer->Start(); + + m_fout = stdout; + + // Initialize progress string + const size_t buffer_length = title.size() + m_nb_plusses_total + 64; + m_buffer = new char[buffer_length]; + // Composes a string with the same text that would be printed + // if format was used on printf, but instead of being printed, + // the content is stored in the buffer. + snprintf(m_buffer, buffer_length, "\r%s: [", title.c_str()); + + // A C string is as long as the number of characters between + // the beginning of the string and the terminating null character + // (without including the terminating null character itself). + m_current_pos = m_buffer + strlen(m_buffer); + char *s = m_current_pos; + for (uint32_t i = 0; i < m_nb_plusses_total; ++i) { + *s++ = ' '; + } + *s++ = ']'; + *s++ = ' '; + *s++ = '\0'; + + if (general_configuration.IsQuiet()) { + // Do not output the progression in quiet mode. + return; + } + + // Write the buffer to the output file stream. + fputs(m_buffer, m_fout); + + // If the given stream was open for writing + // (or if it was open for updating and the last + // i/o operation was an output operation) + // any unwritten data in its output buffer is written + // to the output file stream. + fflush(m_fout); + } + + ProgressReporter::~ProgressReporter() { + delete[] m_buffer; + delete m_timer; + Mutex::Destroy(m_mutex); + } + + void ProgressReporter::Update(uint32_t nb_work) { + if (nb_work == 0 || general_configuration.IsQuiet()) { + // Do not output the progression in quiet mode. + return; + } + + MutexLock lock(*m_mutex); + + m_nb_work_done += nb_work; + const float percent_done = float(m_nb_work_done) / float(m_nb_work_total); + uint32_t plusses_needed = (uint32_t)round(percent_done * m_nb_plusses_total); + if (plusses_needed > m_nb_plusses_total) { + plusses_needed = m_nb_plusses_total; + } + while (m_nb_plusses_printed < plusses_needed) { + *m_current_pos++ = '+'; + ++m_nb_plusses_printed; + } + + // Write the buffer to the output file stream. + fputs(m_buffer, m_fout); + // Update elapsed time and estimated time to completion + const float seconds = (float)m_timer->Time(); + const float estimation_remaining = seconds / percent_done - seconds; + if (percent_done == 1.0f) { + // Writes the string format to the output file stream. + fprintf(m_fout, " (%.1fs) ", seconds); + } + else { + // Writes the string format to the output file stream. + fprintf(m_fout, " (%.1fs|%.1fs) ", seconds, max(0.0f, estimation_remaining)); + } + + // If the given stream was open for writing + // (or if it was open for updating and the last + // i/o operation was an output operation) + // any unwritten data in its output buffer is written + // to the output file stream. + fflush(m_fout); + } + + void ProgressReporter::Done() { + if (general_configuration.IsQuiet()) { + // Do not output the progression in quiet mode. + return; + } + + MutexLock lock(*m_mutex); + + while (m_nb_plusses_printed < m_nb_plusses_total) { + *m_current_pos++ = '+'; + ++m_nb_plusses_printed; + } + + // Write the buffer to the output file stream. + fputs(m_buffer, m_fout); + // Update elapsed time + const float seconds = (float)m_timer->Time(); + // Writes the string format to the output file stream. + fprintf(m_fout, " (%.1fs) \n", seconds); + + // If the given stream was open for writing + // (or if it was open for updating and the last + // i/o operation was an output operation) + // any unwritten data in its output buffer is written + // to the output file stream. + fflush(m_fout); + } +} \ No newline at end of file diff --git a/MAGE/MAGE/src/logging/progressreporter.hpp b/MAGE/MAGE/src/logging/progressreporter.hpp new file mode 100644 index 000000000..39d067da6 --- /dev/null +++ b/MAGE/MAGE/src/logging/progressreporter.hpp @@ -0,0 +1,94 @@ +#pragma once + +//----------------------------------------------------------------------------- +// Engine Declarations and Definitions +//----------------------------------------------------------------------------- +namespace mage { + + /** + A class of progress reporters. + */ + class ProgressReporter { + + public: + + /** + Constructs a progress reporter. + + @param[in] nb_work + The number of parts of the total work. + @param[in] title + A reference to the title. + @param[in] bar_length + The length of the progress bar. + If 0 the default length will be chosen. + */ + ProgressReporter(uint32_t nb_work, const string &title, uint32_t bar_length = 0); + + /** + Destructs this progress reporter. + */ + virtual ~ProgressReporter(); + + /** + Updates this progress reporter. + + @param[in] nb_work + The number of parts of the total work + that are done. + */ + void Update(uint32_t nb_work = 1); + + /** + Finishes this progress reporter. + */ + void Done(); + + private: + + /** + The number of parts of the total work. + */ + const uint32_t m_nb_work_total; + + /** + The number of parts of the total work that are already done. + */ + uint32_t m_nb_work_done; + + /** + The total number of plusses to output. + */ + uint32_t m_nb_plusses_total; + + /** + The total number of plusses that are already outputted. + */ + uint32_t m_nb_plusses_printed; + + /** + The timer of this progress reporter. + */ + Timer *m_timer; + + /** + The output file stream of this progress reporter. + */ + FILE *m_fout; + + /** + The output buffer of this progress reporter. + */ + char *m_buffer; + + /** + The current (output) position of this progress reporter. + */ + char *m_current_pos; + + /** + The mutex needed for updating this progress reporter. + */ + Mutex *m_mutex; + }; +} diff --git a/MAGE/MAGE/src/logging/timer.cpp b/MAGE/MAGE/src/logging/timer.cpp new file mode 100644 index 000000000..a8020796c --- /dev/null +++ b/MAGE/MAGE/src/logging/timer.cpp @@ -0,0 +1,65 @@ +//----------------------------------------------------------------------------- +// Engine Includes +//----------------------------------------------------------------------------- +#pragma region + +#include "engine.hpp" + +#pragma endregion + +//----------------------------------------------------------------------------- +// Engine Definitions +//----------------------------------------------------------------------------- +namespace mage { + + Timer::Timer() : m_running(false), m_time0(0.0), m_elapsed(0.0) { + // Retrieve the frequency of the performance counter. + // The frequency of the performance counter is fixed at system boot + // and is consistent across all processors. + QueryPerformanceFrequency(&m_performance_frequency); + // Calculate the period of the performance counter. + m_performance_period = 1.0 / ((double)m_performance_frequency.QuadPart); + } + + double Timer::time() { + // Retrieve the current value of the performance counter, + // which is a high resolution (< 1 µs) time stamp + // that can be used for time-interval measurements. + QueryPerformanceCounter(&m_performance_counter); + return (double)m_performance_counter.QuadPart * m_performance_period; + } + + void Timer::Start() { + if (m_running) { + return; + } + m_running = true; + // Resets the initial time stamp. + m_time0 = time(); + } + + void Timer::Stop() { + if (!m_running) { + return; + } + m_running = false; + // Set the elapsed time. + m_elapsed += time() - m_time0; + } + + void Timer::Reset() { + m_running = false; + // Resets the elapsed time. + m_elapsed = 0; + } + + double Timer::Time() { + if (m_running) { + // Set the elapsed time. + m_elapsed += time() - m_time0; + // Resets the initial time stamp. + m_time0 = time(); + } + return m_elapsed; + } +} \ No newline at end of file diff --git a/MAGE/MAGE/src/logging/timer.hpp b/MAGE/MAGE/src/logging/timer.hpp new file mode 100644 index 000000000..de182318c --- /dev/null +++ b/MAGE/MAGE/src/logging/timer.hpp @@ -0,0 +1,96 @@ +#pragma once + +//----------------------------------------------------------------------------- +// Engine Declarations and Definitions +//----------------------------------------------------------------------------- +namespace mage { + + /** + A class of (high precision) timers. + */ + class Timer { + + public: + + /** + Constructs a timer. + */ + Timer(); + + /** + Destructs this timer. + */ + virtual ~Timer() {} + + /** + Starts this timer. + */ + void Start(); + + /** + Stops this timer. + */ + void Stop(); + + /** + Resets this timer. + */ + void Reset(); + + /** + Restarts this timer. + */ + void Restart() { + Reset(); + Start(); + } + + /** + Returns the elapsed time of this timer. + + @return The elapsed time of this timer. + */ + double Time(); + + private: + + /** + Returns the time of this timer. + + @return The time of this timer. + @note This member method encapsulates the performance + of the underlying counter/frequency processing. + */ + double time(); + + /** + The initial time stamp of this timer. + */ + double m_time0; + + /** + The elapsed time of this timer. + */ + double m_elapsed; + + /** + Flag indicating whether this timer is running. + */ + bool m_running; + + /** + The counter of this timer. + */ + LARGE_INTEGER m_performance_counter; + + /** + The frequency of this timer. + */ + LARGE_INTEGER m_performance_frequency; + + /** + The period of this timer. + */ + double m_performance_period; + }; +} \ No newline at end of file