From beff47b8f06aa236d00077b1a952b9d783be1d80 Mon Sep 17 00:00:00 2001 From: Brett Date: Thu, 5 Jan 2023 01:52:56 -0500 Subject: [PATCH] Randoms, String refactor, Time, System, + Profiler improvements --- CMakeLists.txt | 9 +- design.txt | 1 + include/blt/config.h.in | 12 -- include/blt/profiling/profiler.h | 76 ++++++----- include/blt/std/queues.h | 18 ++- include/blt/std/random.h | 16 ++- include/blt/std/string.h | 209 ++++++++++++++----------------- include/blt/std/system.h | 14 +++ include/blt/std/time.h | 64 ++++++++++ src/blt/profiling/profiler.cpp | 31 ----- src/blt/std/system.cpp | 6 + 11 files changed, 250 insertions(+), 206 deletions(-) delete mode 100644 include/blt/config.h.in create mode 100644 include/blt/std/system.h create mode 100644 include/blt/std/time.h create mode 100644 src/blt/std/system.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 172e2ac..412306d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.24) project(BLT) +set(CMAKE_PROJECT_VERSION 0.1a) set(CMAKE_CXX_STANDARD 17) option(BUILD_STD "Build the BLT standard utilities." ON) @@ -18,14 +19,11 @@ else() set(PROFILING_FILES "") endif() +#include parallel hashmaps if the user decided to download the submodule. if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap/CMakeLists.txt) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap/) - set(PHMAP_ENABLED ON) endif() -configure_file(include/blt/config.h.in blt/config.h @ONLY) -# include the config file -include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(include/) message("Standard Files ${STD_FILES}") @@ -35,5 +33,6 @@ message("Current Source: ${CMAKE_CURRENT_SOURCE_DIR}") add_library(BLT ${STD_FILES} ${PROFILING_FILES}) target_include_directories(BLT PUBLIC include/) -target_include_directories(BLT PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) target_link_libraries(BLT phmap) + +message("BLT ${CMAKE_PROJECT_VERSION} Successfully included!") diff --git a/design.txt b/design.txt index 262b4e6..d6d2418 100644 --- a/design.txt +++ b/design.txt @@ -1,2 +1,3 @@ Utility classes start with captials (IE classes which are purely static) everything else is camel cased underscore to conform to what most of the C libs seem to use +Template types should be capital camel case diff --git a/include/blt/config.h.in b/include/blt/config.h.in deleted file mode 100644 index 12106e2..0000000 --- a/include/blt/config.h.in +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Created by Brett on 27/12/22. - * Licensed under GNU General Public License V3.0 - * See LICENSE file for license detail - */ - -#ifndef CMAKE_CONFIG - -#cmakedefine PHMAP_ENABLED - -#define CMAKE_CONFIG -#endif \ No newline at end of file diff --git a/include/blt/profiling/profiler.h b/include/blt/profiling/profiler.h index 7387a20..28e2e91 100644 --- a/include/blt/profiling/profiler.h +++ b/include/blt/profiling/profiler.h @@ -9,58 +9,68 @@ #include #include -#include #include #include - -#ifdef PHMAP_ENABLED - #include -#else - #include -#endif - +#include namespace BLT { struct CapturePoint { + std::string_view name; long point; }; struct CaptureInterval { - CapturePoint start; - CapturePoint end; + long start; + long end; }; -#ifdef PHMAP_ENABLED - typedef phmap::parallel_flat_hash_map INTERVAL_MAP; - typedef phmap::parallel_flat_hash_map> POINT_MAP; - typedef phmap::parallel_flat_hash_map POINT_HISTORY_MAP; - typedef phmap::parallel_flat_hash_map ORDER_MAP; -#else - typedef std::unordered_map INTERVAL_MAP; - typedef std::unordered_map POINT_MAP; - typedef std::unordered_map POINT_HISTORY_MAP; - typedef std::unordered_map ORDER_MAP; -#endif - class Profiler { + /** + * @tparam HASHMAP_TYPE + */ + template class HASHMAP_TYPE> + class profile { private: - INTERVAL_MAP intervals{}; + // profiling intervals. + HASHMAP_TYPE intervals{}; + + // profiling points + std::vector> cyclicPointsHistory{}; std::queue points{}; std::queue cyclicPoints{}; - POINT_HISTORY_MAP cyclicPointsHistory{}; - ORDER_MAP order{}; std::mutex timerLock{}; - int lastOrder = 0; public: - Profiler() = default; - void finishCycle(); - void startInterval(const std::string_view& name); - void endInterval(const std::string_view& name); - void profilerPoint(); + profile() = default; + void finishCycle() { + cyclicPointsHistory.push_back(cyclicPoints); + // im not sure if this is the correct way to clear a queue, there is no function to do so. + cyclicPoints = {}; + } + void startInterval(const std::string_view& name) { + std::scoped_lock lock(timerLock); + CaptureInterval interval{}; + interval.start = System::getCurrentTimeNanoseconds(); + intervals[name] = interval; + } + void endInterval(const std::string_view& name) { + std::scoped_lock lock(timerLock); + intervals[name].end = System::getCurrentTimeNanoseconds(); + } /** - * Uses a separate tracking device that will be reset when finishCycle(); is called. + * Records the current time for the purpose of reconstructing the execution time between points, in order to find the most common cause for performance issues. + * @param name a common name for the point which you are trying to profile. This name should be meaningful as it will be displayed in the output. */ - void profilerPointCyclic(); + void profilerPoint(const std::string_view& name) { + points.push(CapturePoint{name, System::getCurrentTimeNanoseconds()}); + } + /** + * Records the current time for the purpose of reconstructing the execution time between points, in order to find the most common cause for performance issues. + * Uses a separate tracking device that will be reset when finishCycle(); is called. + * @param name a common name for the point which you are trying to profile. This name should be meaningful as it will be displayed in the output. + */ + void profilerPointCyclic(const std::string_view& name) { + cyclicPoints.push(CapturePoint{name, System::getCurrentTimeNanoseconds()}); + } }; } diff --git a/include/blt/std/queues.h b/include/blt/std/queues.h index c21d879..8daa47e 100644 --- a/include/blt/std/queues.h +++ b/include/blt/std/queues.h @@ -55,17 +55,24 @@ namespace BLT { data[insertIndex++] = t; } + /** + * Warning does not contain runtime error checking! + * @return the element at the "front" of the queue. + */ [[nodiscard]] const T& front() const { return data[headIndex]; } void pop() { + // TODO: throw exception when popping would result in a overflow? + // I didn't make it an exception here due to not wanting to import the class. + if (headIndex >= size) + return; headIndex++; - // queue is empty. Clear old data. - if (headIndex >= size){ - delete[] data; - data = new T[size]; - } + } + + bool isEmpty(){ + return headIndex >= size; } ~flat_queue() { @@ -73,6 +80,7 @@ namespace BLT { } }; + // avoid this. it is very slow. template class node_queue { private: diff --git a/include/blt/std/random.h b/include/blt/std/random.h index 7723483..c083a28 100644 --- a/include/blt/std/random.h +++ b/include/blt/std/random.h @@ -16,19 +16,29 @@ namespace BLT { * @tparam dist std::uniform_real_distribution or std::uniform_int_distribution */ template typename dist = std::uniform_real_distribution> - class Random { + class random { private: std::random_device rd; // obtain a random number from hardware std::mt19937 gen; dist* distribution = nullptr; public: - explicit Random(T min = (T)0, T max = (T)1, long seed = 0): gen(std::mt19937(seed)){ + /** + * Construct the random number generator. + * @param min min value possible to generate. (default: 0) + * @param max max value possible to generate. (default: 1) + * @param seed seed to use in generating random values. (default: 0) + */ + explicit random(T min = (T)0, T max = (T)1, long seed = 0): gen(std::mt19937(seed)){ distribution = new dist(min, max); } + /** + * Note the min/max are inclusive and defaults to a **uniform** distribution. + * @return random number between the defined min/max or the default of [0,1]. + */ T get(){ return (*distribution)(gen); } - ~Random(){ + ~random(){ delete distribution; } }; diff --git a/include/blt/std/string.h b/include/blt/std/string.h index 12f40b5..adbcbdb 100644 --- a/include/blt/std/string.h +++ b/include/blt/std/string.h @@ -11,125 +11,100 @@ #include #include #include -#include -namespace BLT { - class String { - public: - /** - * Converts the string into lower case - * @param s string to lower case - * @return a string copy that is all lower case - */ - static inline std::string toLowerCase(const std::string& s) { - std::stringstream str; - std::for_each( - s.begin(), s.end(), [&str](unsigned char ch) { - str << (char) std::tolower(ch); - } - ); - return str.str(); - } - - /** - * Converts the string into upper case - * @param s string to upper case - * @return a string copy that is all upper case - */ - static inline std::string toUpperCase(const std::string& s) { - std::stringstream str; - std::for_each( - s.begin(), s.end(), [&str](unsigned char ch) { - str << (char) std::toupper(ch); - } - ); - return str.str(); - } - - /** - * @return the standard string of time.now - */ - static inline std::string getTimeString() { - auto t = std::time(nullptr); - auto now = std::localtime(&t); - std::stringstream timeString; - timeString << (1900 + now->tm_year); - timeString << "-"; - timeString << (1 + now->tm_mon); - timeString << "-"; - timeString << now->tm_mday; - timeString << " "; - timeString << now->tm_hour; - timeString << ":"; - timeString << now->tm_min; - timeString << ":"; - timeString << now->tm_sec; - return timeString.str(); - } - - // taken from https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c - // extended to return a vector - static inline std::vector split(std::string s, const std::string& delim) { - size_t pos = 0; - std::vector tokens; - while ((pos = s.find(delim)) != std::string::npos) { - auto token = s.substr(0, pos); - tokens.push_back(token); - s.erase(0, pos + delim.length()); +namespace BLT::String { + /** + * Converts the string into lower case + * @param s string to lower case + * @return a string copy that is all lower case + */ + static inline std::string toLowerCase(const std::string& s) { + std::stringstream str; + std::for_each( + s.begin(), s.end(), [&str](unsigned char ch) { + str << (char) std::tolower(ch); } - tokens.push_back(s); - return tokens; - } - - // taken from https://stackoverflow.com/questions/216823/how-to-trim-an-stdstring - // would've preferred to use boost lib but instructions said to avoid external libs - // trim from start (in place) - static inline std::string& ltrim(std::string& s) { - s.erase( - s.begin(), std::find_if( - s.begin(), s.end(), [](unsigned char ch) { - return !std::isspace(ch); - } - )); - return s; - } - - // trim from end (in place) - static inline std::string& rtrim(std::string& s) { - s.erase( - std::find_if( - s.rbegin(), s.rend(), [](unsigned char ch) { - return !std::isspace(ch); - } - ).base(), s.end()); - return s; - } - - // trim from both ends (in place) - static inline std::string& trim(std::string& s) { - ltrim(s); - rtrim(s); - return s; - } - - // trim from start (copying) - static inline std::string ltrim_copy(std::string s) { - ltrim(s); - return s; - } - - // trim from end (copying) - static inline std::string rtrim_copy(std::string s) { - rtrim(s); - return s; - } - - // trim from both ends (copying) - static inline std::string trim_copy(std::string s) { - trim(s); - return s; - } - }; + ); + return str.str(); + } + + /** + * Converts the string into upper case + * @param s string to upper case + * @return a string copy that is all upper case + */ + static inline std::string toUpperCase(const std::string& s) { + std::stringstream str; + std::for_each( + s.begin(), s.end(), [&str](unsigned char ch) { + str << (char) std::toupper(ch); + } + ); + return str.str(); + } + + // taken from https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c + // extended to return a vector + static inline std::vector split(std::string s, const std::string& delim) { + size_t pos = 0; + std::vector tokens; + while ((pos = s.find(delim)) != std::string::npos) { + auto token = s.substr(0, pos); + tokens.push_back(token); + s.erase(0, pos + delim.length()); + } + tokens.push_back(s); + return tokens; + } + + // taken from https://stackoverflow.com/questions/216823/how-to-trim-an-stdstring + // would've preferred to use boost lib but instructions said to avoid external libs + // trim from start (in place) + static inline std::string& ltrim(std::string& s) { + s.erase( + s.begin(), std::find_if( + s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + } + )); + return s; + } + + // trim from end (in place) + static inline std::string& rtrim(std::string& s) { + s.erase( + std::find_if( + s.rbegin(), s.rend(), [](unsigned char ch) { + return !std::isspace(ch); + } + ).base(), s.end()); + return s; + } + + // trim from both ends (in place) + static inline std::string& trim(std::string& s) { + ltrim(s); + rtrim(s); + return s; + } + + // trim from start (copying) + static inline std::string ltrim_copy(std::string s) { + ltrim(s); + return s; + } + + // trim from end (copying) + static inline std::string rtrim_copy(std::string s) { + rtrim(s); + return s; + } + + // trim from both ends (copying) + static inline std::string trim_copy(std::string s) { + trim(s); + return s; + } } #endif //BLT_STRING_H diff --git a/include/blt/std/system.h b/include/blt/std/system.h new file mode 100644 index 0000000..496562a --- /dev/null +++ b/include/blt/std/system.h @@ -0,0 +1,14 @@ +/* + * Created by Brett on 04/01/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ + +#ifndef BLT_SYSTEM_H +#define BLT_SYSTEM_H + +namespace BLT::System { + // TODO: system memory and current CPU usage. (Linux Only currently) +} + +#endif //BLT_SYSTEM_H diff --git a/include/blt/std/time.h b/include/blt/std/time.h new file mode 100644 index 0000000..ddc39ed --- /dev/null +++ b/include/blt/std/time.h @@ -0,0 +1,64 @@ +/* + * Created by Brett on 04/01/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ + +#ifndef BLT_TIME_H +#define BLT_TIME_H + +#include +#include +#include + +namespace BLT::System { + static inline auto getCurrentTimeNanoseconds() { + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); + } + + /** + * Standard time string is formatted as follows: + * Year-Month-Date Hour:Min:Second + * If you do not want a space in the string use getTimeStringFS(); (Time String for easy filesystem) + * @return the BLT standard string of time.now + */ + static inline std::string getTimeString() { + auto t = std::time(nullptr); + auto now = std::localtime(&t); + std::stringstream timeString; + timeString << (1900 + now->tm_year); + timeString << "-"; + timeString << (1 + now->tm_mon); + timeString << "-"; + timeString << now->tm_mday; + timeString << " "; + timeString << now->tm_hour; + timeString << ":"; + timeString << now->tm_min; + timeString << ":"; + timeString << now->tm_sec; + return timeString.str(); + } + /** + * @return the BLT standard string of time.now (See getTimeString()) that is filesystem friendly (FAT compatible). + */ + static inline std::string getTimeStringFS() { + auto t = std::time(nullptr); + auto now = std::localtime(&t); + std::stringstream timeString; + timeString << (1900 + now->tm_year); + timeString << "-"; + timeString << (1 + now->tm_mon); + timeString << "-"; + timeString << now->tm_mday; + timeString << "_"; + timeString << now->tm_hour; + timeString << "-"; + timeString << now->tm_min; + timeString << "-"; + timeString << now->tm_sec; + return timeString.str(); + } +} + +#endif //BLT_TIME_H diff --git a/src/blt/profiling/profiler.cpp b/src/blt/profiling/profiler.cpp index 02a4a78..45a107d 100644 --- a/src/blt/profiling/profiler.cpp +++ b/src/blt/profiling/profiler.cpp @@ -4,38 +4,7 @@ * See LICENSE file for license detail */ #include -#include -#include namespace BLT { - void Profiler::finishCycle() { - - } - - static inline auto getCurrentTimeNanoseconds() { - return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); - } - - void Profiler::startInterval(const std::string_view& name) { - std::scoped_lock lock(timerLock); - CaptureInterval interval{}; - interval.start = {getCurrentTimeNanoseconds()}; - intervals[name] = interval; - } - - void Profiler::endInterval(const std::string_view& name) { - std::scoped_lock lock(timerLock); - intervals[name].end = {getCurrentTimeNanoseconds()}; - order[lastOrder++] = name; - } - - void Profiler::profilerPoint() { - - } - - void Profiler::profilerPointCyclic() { - - } - } \ No newline at end of file diff --git a/src/blt/std/system.cpp b/src/blt/std/system.cpp new file mode 100644 index 0000000..1e7442b --- /dev/null +++ b/src/blt/std/system.cpp @@ -0,0 +1,6 @@ +/* + * Created by Brett on 04/01/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ +#include