Randoms, String refactor, Time, System, + Profiler improvements

v1
Brett 2023-01-05 01:52:56 -05:00
parent f1254d54c3
commit beff47b8f0
11 changed files with 250 additions and 206 deletions

View File

@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.24)
project(BLT) project(BLT)
set(CMAKE_PROJECT_VERSION 0.1a)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
option(BUILD_STD "Build the BLT standard utilities." ON) option(BUILD_STD "Build the BLT standard utilities." ON)
@ -18,14 +19,11 @@ else()
set(PROFILING_FILES "") set(PROFILING_FILES "")
endif() endif()
#include parallel hashmaps if the user decided to download the submodule.
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap/CMakeLists.txt) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap/CMakeLists.txt)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap/) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap/)
set(PHMAP_ENABLED ON)
endif() 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/) include_directories(include/)
message("Standard Files ${STD_FILES}") message("Standard Files ${STD_FILES}")
@ -35,5 +33,6 @@ message("Current Source: ${CMAKE_CURRENT_SOURCE_DIR}")
add_library(BLT ${STD_FILES} ${PROFILING_FILES}) add_library(BLT ${STD_FILES} ${PROFILING_FILES})
target_include_directories(BLT PUBLIC include/) target_include_directories(BLT PUBLIC include/)
target_include_directories(BLT PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(BLT phmap) target_link_libraries(BLT phmap)
message("BLT ${CMAKE_PROJECT_VERSION} Successfully included!")

View File

@ -1,2 +1,3 @@
Utility classes start with captials (IE classes which are purely static) 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 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

View File

@ -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

View File

@ -9,58 +9,68 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <blt/config.h>
#include <mutex> #include <mutex>
#include <queue> #include <queue>
#include <blt/std/time.h>
#ifdef PHMAP_ENABLED
#include <parallel_hashmap/phmap.h>
#else
#include <unordered_map>
#endif
namespace BLT { namespace BLT {
struct CapturePoint { struct CapturePoint {
std::string_view name;
long point; long point;
}; };
struct CaptureInterval { struct CaptureInterval {
CapturePoint start; long start;
CapturePoint end; long end;
}; };
#ifdef PHMAP_ENABLED
typedef phmap::parallel_flat_hash_map<std::string_view, CaptureInterval> INTERVAL_MAP;
typedef phmap::parallel_flat_hash_map<std::string_view, std::queue<CapturePoint>> POINT_MAP;
typedef phmap::parallel_flat_hash_map<std::string_view, POINT_MAP> POINT_HISTORY_MAP;
typedef phmap::parallel_flat_hash_map<int, std::string_view> ORDER_MAP;
#else
typedef std::unordered_map<std::string_view, CaptureInterval> INTERVAL_MAP;
typedef std::unordered_map<std::string_view, CapturePoint> POINT_MAP;
typedef std::unordered_map<std::string_view, CapturePoint> POINT_HISTORY_MAP;
typedef std::unordered_map<int, std::string_view> ORDER_MAP;
#endif
class Profiler { /**
* @tparam HASHMAP_TYPE
*/
template <template<typename, typename> class HASHMAP_TYPE>
class profile {
private: private:
INTERVAL_MAP intervals{}; // profiling intervals.
HASHMAP_TYPE<std::string_view, CaptureInterval> intervals{};
// profiling points
std::vector<std::queue<CapturePoint>> cyclicPointsHistory{};
std::queue<CapturePoint> points{}; std::queue<CapturePoint> points{};
std::queue<CapturePoint> cyclicPoints{}; std::queue<CapturePoint> cyclicPoints{};
POINT_HISTORY_MAP cyclicPointsHistory{};
ORDER_MAP order{};
std::mutex timerLock{}; std::mutex timerLock{};
int lastOrder = 0;
public: public:
Profiler() = default; profile() = default;
void finishCycle(); void finishCycle() {
void startInterval(const std::string_view& name); cyclicPointsHistory.push_back(cyclicPoints);
void endInterval(const std::string_view& name); // im not sure if this is the correct way to clear a queue, there is no function to do so.
void profilerPoint(); 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()});
}
}; };
} }

View File

@ -55,17 +55,24 @@ namespace BLT {
data[insertIndex++] = t; data[insertIndex++] = t;
} }
/**
* Warning does not contain runtime error checking!
* @return the element at the "front" of the queue.
*/
[[nodiscard]] const T& front() const { [[nodiscard]] const T& front() const {
return data[headIndex]; return data[headIndex];
} }
void pop() { 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++; headIndex++;
// queue is empty. Clear old data. }
if (headIndex >= size){
delete[] data; bool isEmpty(){
data = new T[size]; return headIndex >= size;
}
} }
~flat_queue() { ~flat_queue() {
@ -73,6 +80,7 @@ namespace BLT {
} }
}; };
// avoid this. it is very slow.
template<typename T> template<typename T>
class node_queue { class node_queue {
private: private:

View File

@ -16,19 +16,29 @@ namespace BLT {
* @tparam dist std::uniform_real_distribution or std::uniform_int_distribution * @tparam dist std::uniform_real_distribution or std::uniform_int_distribution
*/ */
template<typename T, template<typename = T> typename dist = std::uniform_real_distribution> template<typename T, template<typename = T> typename dist = std::uniform_real_distribution>
class Random { class random {
private: private:
std::random_device rd; // obtain a random number from hardware std::random_device rd; // obtain a random number from hardware
std::mt19937 gen; std::mt19937 gen;
dist<T>* distribution = nullptr; dist<T>* distribution = nullptr;
public: 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); 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(){ T get(){
return (*distribution)(gen); return (*distribution)(gen);
} }
~Random(){ ~random(){
delete distribution; delete distribution;
} }
}; };

View File

@ -11,125 +11,100 @@
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <ctime>
namespace BLT { namespace BLT::String {
class String { /**
public: * Converts the string into lower case
/** * @param s string to lower case
* Converts the string into lower case * @return a string copy that is all 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;
static inline std::string toLowerCase(const std::string& s) { std::for_each(
std::stringstream str; s.begin(), s.end(), [&str](unsigned char ch) {
std::for_each( str << (char) std::tolower(ch);
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<std::string> split(std::string s, const std::string& delim) {
size_t pos = 0;
std::vector<std::string> 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; return str.str();
} }
// 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 * Converts the string into upper case
// trim from start (in place) * @param s string to upper case
static inline std::string& ltrim(std::string& s) { * @return a string copy that is all upper case
s.erase( */
s.begin(), std::find_if( static inline std::string toUpperCase(const std::string& s) {
s.begin(), s.end(), [](unsigned char ch) { std::stringstream str;
return !std::isspace(ch); std::for_each(
} s.begin(), s.end(), [&str](unsigned char ch) {
)); str << (char) std::toupper(ch);
return s; }
} );
return str.str();
// trim from end (in place) }
static inline std::string& rtrim(std::string& s) {
s.erase( // taken from https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
std::find_if( // extended to return a vector
s.rbegin(), s.rend(), [](unsigned char ch) { static inline std::vector<std::string> split(std::string s, const std::string& delim) {
return !std::isspace(ch); size_t pos = 0;
} std::vector<std::string> tokens;
).base(), s.end()); while ((pos = s.find(delim)) != std::string::npos) {
return s; auto token = s.substr(0, pos);
} tokens.push_back(token);
s.erase(0, pos + delim.length());
// trim from both ends (in place) }
static inline std::string& trim(std::string& s) { tokens.push_back(s);
ltrim(s); return tokens;
rtrim(s); }
return s;
} // 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 (copying) // trim from start (in place)
static inline std::string ltrim_copy(std::string s) { static inline std::string& ltrim(std::string& s) {
ltrim(s); s.erase(
return s; s.begin(), std::find_if(
} s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
// trim from end (copying) }
static inline std::string rtrim_copy(std::string s) { ));
rtrim(s); return s;
return s; }
}
// trim from end (in place)
// trim from both ends (copying) static inline std::string& rtrim(std::string& s) {
static inline std::string trim_copy(std::string s) { s.erase(
trim(s); std::find_if(
return s; 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 #endif //BLT_STRING_H

14
include/blt/std/system.h Normal file
View File

@ -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

64
include/blt/std/time.h Normal file
View File

@ -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 <chrono>
#include <ctime>
#include <sstream>
namespace BLT::System {
static inline auto getCurrentTimeNanoseconds() {
return std::chrono::duration_cast<std::chrono::nanoseconds>(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

View File

@ -4,38 +4,7 @@
* See LICENSE file for license detail * See LICENSE file for license detail
*/ */
#include <blt/profiling/profiler.h> #include <blt/profiling/profiler.h>
#include <iostream>
#include <utility>
namespace BLT { namespace BLT {
void Profiler::finishCycle() {
}
static inline auto getCurrentTimeNanoseconds() {
return std::chrono::duration_cast<std::chrono::nanoseconds>(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() {
}
} }

6
src/blt/std/system.cpp Normal file
View File

@ -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 <blt/std/system.h>