Randoms, String refactor, Time, System, + Profiler improvements
parent
f1254d54c3
commit
beff47b8f0
|
@ -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!")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
|
@ -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()});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
data = new T[size];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isEmpty(){
|
||||||
|
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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,11 +11,8 @@
|
||||||
#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
|
* Converts the string into lower case
|
||||||
* @param s string to lower case
|
* @param s string to lower case
|
||||||
|
@ -46,27 +43,6 @@ namespace BLT {
|
||||||
return str.str();
|
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
|
// taken from https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
|
||||||
// extended to return a vector
|
// extended to return a vector
|
||||||
static inline std::vector<std::string> split(std::string s, const std::string& delim) {
|
static inline std::vector<std::string> split(std::string s, const std::string& delim) {
|
||||||
|
@ -129,7 +105,6 @@ namespace BLT {
|
||||||
trim(s);
|
trim(s);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BLT_STRING_H
|
#endif //BLT_STRING_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
|
|
@ -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
|
|
@ -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() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -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>
|
Loading…
Reference in New Issue