From c7d21e1014dd663677e263911b185527405a1fac Mon Sep 17 00:00:00 2001 From: saundersp Date: Sat, 27 Apr 2024 21:08:33 +0200 Subject: [PATCH] cpp : more robust code and added more documentation --- cpp/ViolaJones.cpp | 22 ++--- cpp/ViolaJones.hpp | 14 +-- cpp/ViolaJonesGPU.cu | 10 +- cpp/data.cpp | 58 ++++++------ cpp/data.hpp | 186 ++++++++++++++++--------------------- cpp/gpu_unittest.cu | 6 +- cpp/projet.cpp | 187 +++++++++++++++++++++++++------------- cpp/test.cpp | 17 ++-- cpp/toolbox.cpp | 43 ++++++--- cpp/toolbox_unit_test.cpp | 131 +++++++++++++------------- 10 files changed, 355 insertions(+), 319 deletions(-) diff --git a/cpp/ViolaJones.cpp b/cpp/ViolaJones.cpp index 92f75c3..93b7be7 100644 --- a/cpp/ViolaJones.cpp +++ b/cpp/ViolaJones.cpp @@ -2,7 +2,6 @@ #include "data.hpp" #include "config.hpp" #include "ViolaJonesGPU.hpp" -#include "ViolaJonesCPU.hpp" static inline void add_empty_feature(const np::Array& feats, size_t& n) noexcept { memset(&feats[n], 0, 4 * sizeof(uint8_t)); @@ -110,11 +109,11 @@ np::Array build_features(const uint16_t& width, const uint16_t& height) return feats; } -//np::Array select_percentile(const np::Array X_feat, const np::Array y) noexcept { +//np::Array select_percentile(const np::Array X_feat, const np::Array y) noexcept { // std::vector class_0, class_1; // -// const int im_size = X_feat.shape[0] / y.shape[0]; -// int idy = 0, n_samples_per_class_0 = 0, n_samples_per_class_1 = 0; +// const int32_t im_size = X_feat.shape[0] / y.shape[0]; +// int32_t idy = 0, n_samples_per_class_0 = 0, n_samples_per_class_1 = 0; // for (size_t i = 0; i < X_feat.shape[0]; i += im_size) { // if (y[idy] == 0) { // ++n_samples_per_class_0; @@ -126,24 +125,24 @@ np::Array build_features(const uint16_t& width, const uint16_t& height) // } // ++idy; // } -// const int n_samples = n_samples_per_class_0 + n_samples_per_class_1; +// const int32_t n_samples = n_samples_per_class_0 + n_samples_per_class_1; // // float64_t ss_alldata_0 = 0; -// for (int i = 0;i < n_samples_per_class_0;++i) +// for (int32_t i = 0;i < n_samples_per_class_0;++i) // ss_alldata_0 += (class_0[i] * class_0[i]); // // float64_t ss_alldata_1 = 0; -// for (int i = 0;i < n_samples_per_class_1;++i) +// for (int32_t i = 0;i < n_samples_per_class_1;++i) // ss_alldata_1 += (class_1[i] * class_1[i]); // // const float64_t ss_alldata = ss_alldata_0 + ss_alldata_1; // // float64_t sums_classes_0 = 0; -// for (int i = 0;i < n_samples_per_class_0;++i) +// for (int32_t i = 0;i < n_samples_per_class_0;++i) // sums_classes_0 += class_0[i]; // // float64_t sums_classes_1 = 0; -// for (int i = 0;i < n_samples_per_class_1;++i) +// for (int32_t i = 0;i < n_samples_per_class_1;++i) // sums_classes_1 += class_1[i]; // // float64_t sq_of_sums_alldata = sums_classes_0 + sums_classes_1; @@ -154,11 +153,11 @@ np::Array build_features(const uint16_t& width, const uint16_t& height) // const float64_t ss_tot = ss_alldata - sq_of_sums_alldata / n_samples; // const float64_t sqd_sum_bw_n = sq_of_sums_args_0 / n_samples_per_class_0 + sq_of_sums_args_1 / n_samples_per_class_1 - sq_of_sums_alldata / n_samples; // const float64_t ss_wn = ss_tot - sqd_sum_bw_n; -// const int df_wn = n_samples - 2; +// const int32_t df_wn = n_samples - 2; // const float64_t msw = ss_wn / df_wn; // const float64_t f_values = sqd_sum_bw_n / msw; // -// const np::Array res = np::empty({ static_cast(std::ceil(static_cast(im_size) / 10.0)) }); +// const np::Array res = np::empty({ static_cast(std::ceil(static_cast(im_size) / 10.0)) }); // // TODO Complete code // return res; //} @@ -293,4 +292,3 @@ std::tuple confusion_matrix(const np::Ar ++false_positive; return std::make_tuple(true_negative, false_positive, false_negative, true_positive); } - diff --git a/cpp/ViolaJones.hpp b/cpp/ViolaJones.hpp index 7a2e387..08bcff9 100644 --- a/cpp/ViolaJones.hpp +++ b/cpp/ViolaJones.hpp @@ -112,9 +112,9 @@ template std::array, N> state_saver(const char* const step_name, const int32_t& column_width, const std::vector& filenames, const bool& force_redo, const bool& save_state, const char* const out_dir, const F& fnc, Args &&...args) noexcept { char filepath[BUFFER_SIZE] = { 0 }; bool abs = false; - for (const char* filename : filenames){ - sprintf(filepath, "%s/%s.bin", out_dir, filename); - if (!fs::exists(filepath)) { + for (const char* const filename : filenames){ + snprintf(filepath, BUFFER_SIZE, "%s/%s.bin", out_dir, filename); + if (!std::filesystem::exists(filepath)) { abs = true; break; } @@ -130,8 +130,8 @@ std::array, N> state_saver(const char* const step_name, const int32 fflush(stderr); #endif size_t i = 0; - for (const char* filename : filenames){ - sprintf(filepath, "%s/%s.bin", out_dir, filename); + for (const char* const filename : filenames){ + snprintf(filepath, BUFFER_SIZE, "%s/%s.bin", out_dir, filename); save(bin[i++], filepath); } #if __DEBUG == false @@ -145,8 +145,8 @@ std::array, N> state_saver(const char* const step_name, const int32 fflush(stderr); #endif size_t i = 0; - for (const char* filename : filenames){ bin[i++] = std::move(load(filepath)); + for (const char* const filename : filenames){ snprintf(filepath, BUFFER_SIZE, "%s/%s.bin", out_dir, filename); } formatted_row<3>({ column_width, -18, 29 }, { step_name, "None", "loaded saved state" }); @@ -156,7 +156,7 @@ std::array, N> state_saver(const char* const step_name, const int32 np::Array argsort_2d_cpu(const np::Array&) noexcept; np::Array build_features(const uint16_t&, const uint16_t&) noexcept; -np::Array select_percentile(const np::Array&, const np::Array&) noexcept; +np::Array select_percentile(const np::Array&, const np::Array&) noexcept; np::Array classify_viola_jones(const np::Array&, const np::Array&, const np::Array&) noexcept; np::Array init_weights(const np::Array&) noexcept; std::tuple> select_best(const np::Array&, const np::Array&, const np::Array&, diff --git a/cpp/ViolaJonesGPU.cu b/cpp/ViolaJonesGPU.cu index 0caa5ba..b491aed 100644 --- a/cpp/ViolaJonesGPU.cu +++ b/cpp/ViolaJonesGPU.cu @@ -180,7 +180,7 @@ static __global__ void __apply_feature_kernel__(int32_t* d_X_feat, const np::Arr np::Array apply_features_gpu(const np::Array& feats, const np::Array& X_ii) noexcept { const np::Array X_feat = np::empty({ feats.shape[0], X_ii.shape[0] }); - int32_t* d_X_feat; + int32_t* d_X_feat = nullptr; _print_cuda_error_("malloc d_X_feat", cudaMalloc(&d_X_feat, np::prod(X_feat.shape) * sizeof(int32_t))); np::Array d_X_ii = copyToDevice("X_ii", X_ii); @@ -268,7 +268,7 @@ np::Array train_weak_clf_gpu(const np::Array& X_feat, const } template -__device__ inline static int32_t as_partition_gpu(const T* a, uint16_t* indices, const size_t l, const size_t h) noexcept { +__device__ inline static int32_t as_partition_gpu(const T* a, uint16_t* const indices, const size_t l, const size_t h) noexcept { int32_t i = l - 1; for (int32_t j = l; j <= h; ++j) if (a[indices[j]] < a[indices[h]]) @@ -278,7 +278,7 @@ __device__ inline static int32_t as_partition_gpu(const T* a, uint16_t* indices, } template -__device__ void argsort_gpu(const T* a, uint16_t* indices, const size_t l, const size_t h) noexcept { +__device__ void argsort_gpu(const T* a, uint16_t* const indices, const size_t l, const size_t h) noexcept { const size_t total = h - l + 1; //int32_t* stack = new int32_t[total]{l, h}; @@ -312,7 +312,7 @@ __device__ void argsort_gpu(const T* a, uint16_t* indices, const size_t l, const } template -__global__ void argsort_bounded_gpu(const np::Array a, uint16_t* indices){ +__global__ void argsort_bounded_gpu(const np::Array a, uint16_t* const indices){ const size_t idx = blockIdx.x * blockDim.x + threadIdx.x; if (idx >= a.shape[0]) return; @@ -324,7 +324,7 @@ __global__ void argsort_bounded_gpu(const np::Array a, uint16_t* indices){ np::Array argsort_2d_gpu(const np::Array& X_feat) noexcept { const np::Array indices = np::empty(X_feat.shape); - uint16_t* d_indices; + uint16_t* d_indices = nullptr; const size_t indices_size = np::prod(indices.shape) * sizeof(uint16_t); np::Array d_X_feat = copyToDevice("X_feat", X_feat); diff --git a/cpp/data.cpp b/cpp/data.cpp index 676da1c..38b13f0 100644 --- a/cpp/data.cpp +++ b/cpp/data.cpp @@ -1,9 +1,7 @@ #include "data.hpp" -//#include "toolbox.hpp" -//#include -int print(const np::Shape& shape) noexcept { - int num_written = 0; +int32_t print(const np::Shape& shape) noexcept { + int32_t num_written = 0; num_written += printf("("); if (shape.length > 1) { const size_t length = shape.length - 1; @@ -17,7 +15,7 @@ int print(const np::Shape& shape) noexcept { } template -int print(const np::Array& array, const char* format) noexcept { +int32_t print(const np::Array& array, const char* const format) noexcept { //printf("["); //const size_t length = np::prod(array.shape); //for(size_t i = 0; i < length - 1; ++i) @@ -27,10 +25,10 @@ int print(const np::Array& array, const char* format) noexcept { //printf("%f]\n", array[length - 1]); char format_space[BUFFER_SIZE] = { 0 }; - sprintf(format_space, "%s ", format); + snprintf(format_space, BUFFER_SIZE,"%s ", format); char format_close[BUFFER_SIZE] = { 0 }; - sprintf(format_close, "%s]\n", format); - int num_written = 0; + snprintf(format_close, BUFFER_SIZE,"%s]\n", format); + int32_t num_written = 0; if (array.shape.length == 1) { const size_t max = array.shape[0] - 1; @@ -53,16 +51,16 @@ int print(const np::Array& array, const char* format) noexcept { return num_written; } -int print(const np::Array& array) noexcept { +int32_t print(const np::Array& array) noexcept { return print(array, "%hu"); } -int print(const np::Array& array) noexcept { +int32_t print(const np::Array& array) noexcept { return print(array, "%f"); } -int print_feat(const np::Array& array, const np::Slice& slice) noexcept { - int num_written = 0; +int32_t print_feat(const np::Array& array, const np::Slice& slice) noexcept { + int32_t num_written = 0; num_written += printf("["); const size_t feat_size = np::prod(array.shape, 1); const size_t offset = slice.x * feat_size; @@ -74,8 +72,8 @@ int print_feat(const np::Array& array, const np::Slice& slice) noexcept return num_written; } -int print(const np::Array& array, const np::Slice& slice) noexcept { - int num_written = 0; +int32_t print(const np::Array& array, const np::Slice& slice) noexcept { + int32_t num_written = 0; if (array.shape.length == 1) { const size_t max = slice.y - 1; //std::min(slice.y, array.shape[0] - 1); num_written += printf("["); @@ -97,8 +95,8 @@ int print(const np::Array& array, const np::Slice& slice) noexcept { return num_written; } -int print(const np::Array& array, const np::Slice& slice) noexcept { - int num_written = 0; +int32_t print(const np::Array& array, const np::Slice& slice) noexcept { + int32_t num_written = 0; if (array.shape.length == 1) { const size_t max = slice.y - 1; //std::min(slice.y, array.shape[0] - 1); num_written += printf("["); @@ -115,37 +113,37 @@ int print(const np::Array& array, const np::Slice& slice) noexcept { num_written += printf("%5i ", array[k + i * array.shape[1] + j]); num_written += printf("]\n"); } - num_written += print("]"); + num_written += printf("]"); } return num_written; } -int print(const np::Array& array, const np::Slice& slice) noexcept { - int num_written = 0; +int32_t print(const np::Array& array, const np::Slice& slice) noexcept { + int32_t num_written = 0; num_written += printf("["); //size_t k = slice.x * array.shape[1] * array.shape[2] + slice.y * array.shape[2] + slice.z; size_t k = slice.x * array.shape[1]; for (size_t i = k; i < k + (slice.y - slice.x); ++i) { num_written += printf("%5i ", array[i]); } - num_written += print("]"); + num_written += printf("]"); return num_written; } -int print(const np::Array& array, const np::Slice& slice) noexcept { - int num_written = 0; +int32_t print(const np::Array& array, const np::Slice& slice) noexcept { + int32_t num_written = 0; num_written += printf("["); //size_t k = slice.x * array.shape[1] * array.shape[2] + slice.y * array.shape[2] + slice.z; size_t k = slice.x * array.shape[1]; for (size_t i = k; i < k + (slice.y - slice.x); ++i) { num_written += printf("%5hu ", array[i]); } - num_written += print("]"); + num_written += printf("]"); return num_written; } -static inline np::Array load_set(const char* set_name) { - FILE* file = fopen(set_name, "rb"); +static inline np::Array load_set(const char* const set_name) { + FILE* const file = fopen(set_name, "rb"); if (file == NULL) { print_error_file(set_name); throw; @@ -156,7 +154,7 @@ static inline np::Array load_set(const char* set_name) { fclose(file); throw; } - size_t* dims = new size_t[3](); + size_t* const dims = new size_t[3](); if (!sscanf(meta, "%lu %lu %lu", &dims[0], &dims[1], &dims[2])) { print_error_file(set_name); fclose(file); @@ -167,7 +165,7 @@ static inline np::Array load_set(const char* set_name) { const size_t size = np::prod(a.shape); size_t i = 0, j = 0; - int c; + int32_t c; char buff[STRING_INT_SIZE] = { 0 }; while ((c = fgetc(file)) != EOF && i < size) { if (c == ' ' || c == '\n') { @@ -191,15 +189,15 @@ static inline np::Array load_set(const char* set_name) { return a; } -std::array, 4> load_datasets() { +std::array, 4> load_datasets(void) { return { load_set(DATA_DIR "/X_train.bin"), load_set(DATA_DIR "/y_train.bin"), load_set(DATA_DIR "/X_test.bin"), load_set(DATA_DIR "/y_test.bin") }; } -void print_error_file(const char* file_dir) noexcept { - const char* buff = strerror(errno); +void print_error_file(const char* const file_dir) noexcept { + const char* const buff = strerror(errno); fprintf(stderr, "Can't open %s, error code = %d : %s\n", file_dir, errno, buff); // delete buff; } diff --git a/cpp/data.hpp b/cpp/data.hpp index 6154eff..871e032 100644 --- a/cpp/data.hpp +++ b/cpp/data.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "config.hpp" #define BUFFER_SIZE 256 @@ -19,15 +19,6 @@ typedef float float32_t; typedef double float64_t; typedef long double float128_t; -__host__ __device__ -constexpr inline int print(const char* str) noexcept { - return printf("%s\n", str); -} - -inline int print(const std::string& s) noexcept { - return printf("%s\n", s.c_str()); -} - namespace np { constexpr const float64_t inf = std::numeric_limits::infinity(); @@ -44,16 +35,16 @@ namespace np { #endif __host__ __device__ - Shape() noexcept { // #if __DEBUG // print("Shape created (default)"); // #endif + Shape(void) noexcept { } __host__ __device__ - Shape(const size_t& length, size_t* data) noexcept : length(length), data(data), refcount(new size_t(1)) { + Shape(const size_t& length, size_t* const data) noexcept : length(length), data(data), refcount(new size_t(1)) { #if __DEBUG - //print("Shape created (raw)"); + printf("Shape created (raw)\n"); for(size_t i = 0; i < length; ++i) total *= data[i]; #endif @@ -64,7 +55,7 @@ namespace np { // #if __DEBUG // print("Shape created (initializer)"); // #endif - const size_t* begin = dims.begin(); + const size_t* const begin = dims.begin(); for(size_t i = 0; i < length; ++i){ data[i] = begin[i]; #if __DEBUG @@ -76,34 +67,31 @@ namespace np { __host__ __device__ Shape(const Shape& shape) noexcept { #if __DEBUG - print("Shape created (copy)"); + printf("Shape created (copy)\n"); #endif if (data != nullptr && data != shape.data){ #if __DEBUG - print("Former shape deleted (copy)"); + printf("Former shape deleted (copy)\n"); #endif delete[] data; } if (refcount != nullptr && refcount != shape.refcount){ #if __DEBUG - print("Former shape refcount freed (copy)"); + printf("Former shape refcount freed (copy)\n"); #endif delete refcount; } length = shape.length; - - //data = new size_t[length]; - //memcpy(data, shape.data, length * sizeof(size_t)); - //refcount = new size_t; - //memcpy(refcount, shape.refcount, sizeof(size_t)); - data = shape.data; refcount = shape.refcount; + if (refcount != nullptr) (*refcount)++; #if __DEBUG else - print("Moved shape has null refcount"); + printf("Moved shape has null refcount\n"); +#endif +#if __DEBUG total = shape.total; #endif } @@ -115,13 +103,13 @@ namespace np { // #endif if (data != nullptr && data != shape.data){ #if __DEBUG - print("Former shape deleted (move)"); + printf("Former shape deleted (move)\n"); #endif delete[] data; } if (refcount != nullptr && refcount != shape.refcount){ #if __DEBUG - print("Former shape refcount freed (move)"); + printf("Former shape refcount freed (move)\n"); #endif delete refcount; } @@ -139,7 +127,7 @@ namespace np { } __host__ __device__ - ~Shape() noexcept { + ~Shape(void) noexcept { if(refcount == nullptr){ // #if __DEBUG // print("Shape refcount freed more than once"); @@ -173,34 +161,29 @@ namespace np { __host__ __device__ Shape& operator=(const Shape& shape) noexcept { #if __DEBUG - print("Shape created (assign copy)"); + printf("Shape created (assign copy)\n"); #endif if (data != nullptr && data != shape.data){ #if __DEBUG - print("Former shape deleted (assign copy)"); + printf("Former shape deleted (assign copy)\n"); #endif delete[] data; } if (refcount != nullptr && refcount != shape.refcount){ #if __DEBUG - print("Former shape refcount freed (assign copy)"); + printf("Former shape refcount freed (assign copy)\n"); #endif delete refcount; } length = shape.length; - - // data = new size_t[length]; - // memcpy(data, shape.data, length * sizeof(size_t)); - // refcount = new size_t; - // memcpy(refcount, shape.refcount, sizeof(size_t)); - data = shape.data; refcount = shape.refcount; + if (refcount != nullptr) (*refcount)++; #if __DEBUG else - printf("Assigned copy shape has null refcount"); + printf("Assigned copy shape has null refcount\n"); total = shape.total; #endif return *this; @@ -213,13 +196,13 @@ namespace np { // #endif if (data != nullptr && data != shape.data){ #if __DEBUG - print("Former shape deleted (assign move)"); + printf("Former shape deleted (assign move)\n"); #endif delete[] data; } if (refcount != nullptr && refcount != shape.refcount){ #if __DEBUG - print("Former shape refcount freed (assign move)"); + printf("Former shape refcount freed (assign move)\n"); #endif delete refcount; } @@ -228,8 +211,6 @@ namespace np { refcount = shape.refcount; #if __DEBUG total = shape.total; - if (refcount == nullptr) - print("Assigned copy shape has null refcount"); shape.total = 1; #endif shape.length = 0; @@ -280,17 +261,16 @@ namespace np { size_t* refcount = nullptr; __host__ __device__ - Array() noexcept { // #if __DEBUG // print("Array created (default)"); -// #endif + Array(void) noexcept { } __host__ __device__ - Array(const Shape& shape, T* data) noexcept : shape(shape), data(data), refcount(new size_t(1)) { // #if __DEBUG // print("Array created (raw, copy shape)"); // #endif + Array(const Shape& shape, T* const data) noexcept : shape(shape), data(data), refcount(new size_t(1)) { } __host__ __device__ @@ -301,41 +281,36 @@ namespace np { } __host__ __device__ - Array(Shape&& shape, T* data) noexcept : shape(std::move(shape)), data(data), refcount(new size_t(1)) { // #if __DEBUG // print("Array created (raw, move shape)"); // #endif + Array(Shape&& shape, T* const data) noexcept : shape(shape), data(data), refcount(new size_t(1)) { } __host__ __device__ - Array(Shape&& shape) noexcept : shape(std::move(shape)), data(new T[np::prod(shape)]), refcount(new size_t(1)) { // #if __DEBUG // print("Array created (raw empty, move shape)"); // #endif + Array(Shape&& shape) noexcept : shape(shape), data(new T[np::prod(shape)]), refcount(new size_t(1)) { } __host__ __device__ Array(const Array& array) noexcept : shape(array.shape) { #if __DEBUG - print("Array created (copy)"); + printf("Array created (copy)\n"); #endif if (data != nullptr && data != array.data){ -#ifdef __debug - print("Former array deleted (move)"); +#if __DEBUG + printf("Former array deleted (copy)\n"); #endif delete[] data; } if (refcount != nullptr && refcount != array.refcount){ #if __DEBUG - print("Former array refcount freed (move)"); + printf("Former array refcount freed (copy)\n"); #endif delete refcount; } - // const size_t size = np::prod(shape); - // data = new T[size]; - // memcpy(data, array.data, size); - // refcount = new size_t; - // memcpy(refcount, array.refcount, sizeof(size_t)); data = array.data; refcount = array.refcount; @@ -343,28 +318,27 @@ namespace np { (*refcount)++; #if __DEBUG else - print("Moved array has null refcount"); + printf("Moved array has null refcount\n"); #endif } __host__ __device__ - Array(Array&& array) noexcept { // #if __DEBUG // print("Array created (move)"); // #endif + Array(Array&& array) noexcept : shape(std::move(array.shape)) { if (data != nullptr && data != array.data){ #if __DEBUG - print("Former array deleted (move)"); + printf("Former array deleted (move)\n"); #endif delete[] data; } if (refcount != nullptr && refcount != array.refcount){ #if __DEBUG - print("Former array refcount freed (move)"); + printf("Former array refcount freed (move)\n"); #endif delete refcount; } - shape = std::move(array.shape); data = array.data; refcount = array.refcount; @@ -373,7 +347,7 @@ namespace np { } __host__ __device__ - ~Array() noexcept { + ~Array(void) noexcept { if(refcount == nullptr){ // #if __DEBUG // print("Array refcount freed more than once"); @@ -404,36 +378,30 @@ namespace np { __host__ __device__ Array& operator=(const Array& array) noexcept { #if __DEBUG - print("Array created (assign copy)"); + printf("Array created (assign copy)\n"); #endif if (data != nullptr && data != array.data){ #if __DEBUG - print("Former array deleted (assign copy)"); + printf("Former array deleted (assign copy)\n"); #endif delete[] data; } if (refcount != nullptr && refcount != array.refcount){ #if __DEBUG - print("Former array refcount freed (assign copy)"); + printf("Former array refcount freed (assign copy)\n"); #endif delete refcount; } shape = array.shape; - - // const size_t size = np::prod(shape) * sizeof(T); - // data = new T[size]; - // memcpy(data, array.data, size); - // refcount = new size_t; - // memcpy(refcount, array.refcount, sizeof(size_t)); - data = array.data; refcount = array.refcount; + if (refcount != nullptr) (*refcount)++; #if __DEBUG else - print("Assigned array has null refcount"); #endif + printf("Assigned array has null refcount\n"); return *this; } @@ -444,13 +412,13 @@ namespace np { // #endif if (data != nullptr && data != array.data){ #if __DEBUG - print("Former array deleted (assign move)"); + printf("Former array deleted (assign move)\n"); #endif delete[] data; } if (refcount != nullptr && refcount != array.refcount){ #if __DEBUG - print("Former array refcount freed (assign move)"); + printf("Former array refcount freed (assign move)\n"); #endif delete refcount; } @@ -485,35 +453,39 @@ namespace np { }; template - Array empty(Shape&& shape) noexcept { - return { std::move(shape), new T[np::prod(shape)] }; + inline Array empty(Shape&& shape) noexcept { + return Array(shape); } template - Array empty(const Shape& shape) noexcept { - return { std::move(shape), new T[np::prod(shape)] }; + inline Array empty(const Shape& shape) noexcept { + return Array(shape); } template - Array empty(const std::initializer_list& dims) noexcept { - const Shape shape(dims); - return { std::move(shape), new T[np::prod(shape)] }; + inline Array empty(const std::initializer_list& dims) noexcept { + return Array(dims); } template Array zeros(Shape&& shape) noexcept { - return { std::move(shape), new T[np::prod(shape)]{0} }; + Array res(shape); + memset(res.data, 0, sizeof(T) * np::prod(res.shape)); + return res; } template Array zeros(const Shape& shape) noexcept { - return { std::move(shape), new T[np::prod(shape)]{0} }; + Array res(shape); + memset(res.data, 0, sizeof(T) * np::prod(res.shape)); + return res; } template Array zeros(const std::initializer_list& dims) noexcept { - const Shape shape(dims); - return { std::move(shape), new T[np::prod(shape)]{0} }; + Array res(dims); + memset(res.data, 0, sizeof(T) * np::prod(res.shape)); + return res; } template @@ -773,7 +745,7 @@ constexpr np::Array& map(np::Array& a, const std::function __host__ __device__ -constexpr inline static void swap(T* a, T* b) noexcept { +constexpr inline static void swap(T* const a, T* const b) noexcept { if (a == b) return; const T temp = *a; *a = *b; @@ -805,7 +777,7 @@ void quicksort(const np::Array& a) noexcept { } template -static size_t as_partition(const T* a, uint16_t* indices, const size_t& l, const size_t& h) noexcept { +static size_t as_partition(const T* const a, uint16_t* const indices, const size_t& l, const size_t& h) noexcept { size_t i = l - 1; for (size_t j = l; j <= h; ++j) if (a[indices[j]] < a[indices[h]]) @@ -815,10 +787,10 @@ static size_t as_partition(const T* a, uint16_t* indices, const size_t& l, const } template -void argsort(const T* a, uint16_t* indices, const size_t& l, const size_t& h) noexcept { +void argsort(const T* const a, uint16_t* const indices, const size_t& l, const size_t& h) noexcept { const size_t total = h - l + 1; - size_t* stack = new size_t[total]{l, h}; + size_t* const stack = new size_t[total]{l, h}; size_t top = 1, low = l, high = h; while (top <= total) { @@ -852,16 +824,16 @@ np::Array argsort(const np::Array& other, const size_t& l, const si } template -np::Array argsort(const np::Array* other, const size_t& length) noexcept { +np::Array argsort(const np::Array* const other, const size_t& length) noexcept { return argsort(other, 0, length - 1); } std::array, 4> load_datasets(void); -void print_error_file(const char*) noexcept; +void print_error_file(const char* const) noexcept; template -void save(const np::Array& d, const char* filename) { - FILE* output = fopen(filename, "wb"); +void save(const np::Array& d, const char* const filename) { + FILE* const output = fopen(filename, "wb"); if (output == NULL) { print_error_file(filename); throw; @@ -875,8 +847,8 @@ void save(const np::Array& d, const char* filename) { } template -np::Array load(const char* filename) { - FILE* input = fopen(filename, "rb"); +np::Array load(const char* const filename) { + FILE* const input = fopen(filename, "rb"); if (input == NULL) { print_error_file(filename); throw; @@ -887,7 +859,7 @@ np::Array load(const char* filename) { fclose(input); throw; } - size_t* data = new size_t[length]; + size_t* const data = new size_t[length]; if(!fread(data, sizeof(size_t), length, input)){ print_error_file(filename); fclose(input); @@ -905,7 +877,7 @@ np::Array load(const char* filename) { #ifdef __CUDACC__ template -np::Array copyToDevice(const char* name, const np::Array& array) noexcept { +np::Array copyToDevice(const char* const name, const np::Array& array) noexcept { const size_t array_size = np::prod(array.shape) * sizeof(T); const size_t shape_size = array.shape.length * sizeof(size_t); np::Array d_array; @@ -925,7 +897,7 @@ np::Array copyToDevice(const char* name, const np::Array& array) noexcept } template -constexpr void cudaFree(const char* name, np::Array& array) noexcept { +constexpr void cudaFree(const char* const name, np::Array& array) noexcept { //_print_cuda_error_(name, cudaFree(array.refcount)); //array.refcount = nullptr; _print_cuda_error_(name, cudaFree(array.data)); @@ -936,16 +908,16 @@ constexpr void cudaFree(const char* name, np::Array& array) noexcept { array.shape.data = nullptr; } -constexpr inline void _print_cuda_error_(const char* name, const cudaError_t& err) noexcept { +constexpr inline void _print_cuda_error_(const char* const name, const cudaError_t& err) noexcept { if (err != cudaSuccess) fprintf(stderr, "Error: %s = %d : %s\n", name, err, cudaGetErrorString(err)); } #endif -int print(const np::Shape&) noexcept; -int print(const np::Array&) noexcept; -int print(const np::Array&) noexcept; -int print(const np::Array&, const np::Slice&) noexcept; -int print(const np::Array&, const np::Slice&) noexcept; -int print(const np::Array&, const np::Slice&) noexcept; -int print(const np::Array&, const np::Slice&) noexcept; -int print_feat(const np::Array&, const np::Slice&) noexcept; +int32_t print(const np::Shape&) noexcept; +int32_t print(const np::Array&) noexcept; +int32_t print(const np::Array&) noexcept; +int32_t print(const np::Array&, const np::Slice&) noexcept; +int32_t print(const np::Array&, const np::Slice&) noexcept; +int32_t print(const np::Array&, const np::Slice&) noexcept; +int32_t print(const np::Array&, const np::Slice&) noexcept; +int32_t print_feat(const np::Array&, const np::Slice&) noexcept; diff --git a/cpp/gpu_unittest.cu b/cpp/gpu_unittest.cu index e16176e..f5ea544 100644 --- a/cpp/gpu_unittest.cu +++ b/cpp/gpu_unittest.cu @@ -11,7 +11,7 @@ void test_working(const size_t& length) noexcept { const size_t size = length * sizeof(size_t); #if __DEBUG - print("Estimating memory footprint at : " + format_byte_size(2 * size)); + printf("Estimating memory footprint at : %s\n", format_byte_size(2 * size).c_str()); #endif np::Array x = np::empty({ length }), y = np::empty({ length }); @@ -53,7 +53,7 @@ void test_working_2d(const size_t& N1, const size_t& N2) noexcept { const size_t size = length * sizeof(size_t); #if __DEBUG - print("Estimating memory footprint at : " + format_byte_size(2 * size)); + printf("Estimating memory footprint at : %s\n", format_byte_size(2 * size).c_str()); #endif np::Array x = np::empty({ length }), y = np::empty({ length }); @@ -96,7 +96,7 @@ void test_working_3d(const size_t& N1, const size_t& N2, const size_t& N3) noexc const size_t size = length * sizeof(size_t); #if __DEBUG - print("Estimating memory footprint at : " + format_byte_size(2 * size)); + printf("Estimating memory footprint at : %s\n", format_byte_size(2 * size).c_str()); #endif np::Array x = np::empty({ length }), y = np::empty({ length }); diff --git a/cpp/projet.cpp b/cpp/projet.cpp index 48d6730..a0e06f9 100644 --- a/cpp/projet.cpp +++ b/cpp/projet.cpp @@ -1,50 +1,61 @@ #include -namespace fs = std::filesystem; #include "data.hpp" #include "toolbox.hpp" #include "config.hpp" -#include "gpu_unit_test.hpp" #include "toolbox_unit_test.hpp" #include "ViolaJones.hpp" -#include "ViolaJonesGPU.hpp" -#include "ViolaJonesCPU.hpp" #if GPU_BOOSTED +#include "ViolaJonesGPU.hpp" +#include "gpu_unit_test.hpp" #define LABEL "GPU" #define apply_features apply_features_gpu #define set_integral_image set_integral_image_gpu #define argsort_2d argsort_2d_gpu #else +#include "ViolaJonesCPU.hpp" #define LABEL "CPU" #define apply_features apply_features_cpu #define set_integral_image set_integral_image_cpu #define argsort_2d argsort_2d_cpu #endif -std::tuple, np::Array, np::Array, np::Array, np::Array> preprocessing() { +/** + * @brief Execute the preprocessing phase + * + * The preprocessing phase consist of the following steps : + * - Load the dataset + * - Calculate features + * - Calculate integral images + * - Apply features to images + * - Calculate argsort of the featured images. + * + * @return std::tuple, np::Array, np::Array, np::Array, np::Array> Tuple containing in order : training features, training features sorted indexes, training labels, testing features, testing labels + */ +std::tuple, np::Array, np::Array, np::Array, np::Array> preprocessing(void) { // Creating state saver folders if they don't exist already if (SAVE_STATE) for (const char* const folder_name : { "models", "out" }) - fs::create_directory(folder_name); + std::filesystem::create_directory(folder_name); const std::chrono::system_clock::time_point preproc_timestamp = perf_counter_ns(); const std::array preproc_gaps = { 49, -18, 29 }; header({ "Preprocessing", "Time spent (ns)", "Formatted time spent" }, preproc_gaps); - const auto [ X_train, y_train, X_test, y_test ] = state_saver("Loading sets", preproc_gaps[0], {"X_train", "y_train", "X_test", "y_test"}, + const auto [ X_train, y_train, X_test, y_test ] = state_saver("Loading sets", preproc_gaps[0], { "X_train", "y_train", "X_test", "y_test" }, FORCE_REDO, SAVE_STATE, OUT_DIR, load_datasets); #if __DEBUG - print("X_train"); + printf("X_train\n"); print(X_train.shape); print(X_train, { IDX_INSPECT }); - print("X_test"); + printf("X_test\n"); print(X_test.shape); print(X_test, { IDX_INSPECT }); - print("y_train"); + printf("y_train\n"); print(y_train.shape); print(y_train, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); - print("y_test"); + printf("y_test\n"); print(y_test.shape); print(y_test, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); #endif @@ -53,7 +64,7 @@ std::tuple, np::Array, np::Array, np::Arra FORCE_REDO, SAVE_STATE, OUT_DIR, build_features, X_train.shape[1], X_train.shape[2]); #if __DEBUG - print("feats"); + printf("feats\n"); print(feats.shape); print_feat(feats, { IDX_INSPECT }); #endif @@ -64,10 +75,10 @@ std::tuple, np::Array, np::Array, np::Arra FORCE_REDO, SAVE_STATE, OUT_DIR, set_integral_image, X_test); #if __DEBUG - print("X_train_ii"); + printf("X_train_ii\n"); print(X_train_ii.shape); print(X_train_ii, { IDX_INSPECT }); - print("X_test_ii"); + printf("X_test_ii\n"); print(X_test_ii.shape); print(X_test_ii, { IDX_INSPECT }); #endif @@ -78,16 +89,16 @@ std::tuple, np::Array, np::Array, np::Arra FORCE_REDO, SAVE_STATE, OUT_DIR, apply_features, feats, X_test_ii); #if __DEBUG - print("X_train_feat"); + printf("X_train_feat\n"); print(X_train_feat.shape); print(X_train_feat, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); - print("X_test_feat"); + printf("X_test_feat\n"); print(X_test_feat.shape); print(X_test_feat, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); #endif - // const Array indices = measure_time_save>("Selecting best features", "indices", select_percentile, X_train_feat, d.y_train); - // const Array indices = measure_time>("Selecting best features", select_percentile, X_train_feat, d.y_train); + // const np::Array indices = measure_time_save>("Selecting best features", preproc_gaps[0], "indices", select_percentile, X_train_feat, d.y_train); + // const np::Array indices = measure_time>("Selecting best features", preproc_gaps[0], select_percentile, X_train_feat, d.y_train); #if __DEBUG // print_feature(indices); @@ -97,7 +108,7 @@ std::tuple, np::Array, np::Array, np::Arra FORCE_REDO, SAVE_STATE, OUT_DIR, argsort_2d, X_train_feat); #if __DEBUG - print("X_train_feat_argsort"); + printf("X_train_feat_argsort\n"); print(X_train_feat_argsort.shape); print(X_train_feat_argsort, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); #endif @@ -117,6 +128,14 @@ std::tuple, np::Array, np::Array, np::Arra return { X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test }; } +/** + * @brief Train the weak classifiers. + * + * @param X_train_feat Training images. + * @param X_train_feat_argsort Sorted indexes of the training images features. + * @param y_train Training labels. + * @return Trained models + */ std::array, 2>, TS.size()> train(const np::Array& X_train_feat, const np::Array& X_train_feat_argsort, const np::Array& y_train) noexcept { const std::chrono::system_clock::time_point training_timestamp = perf_counter_ns(); const std::array training_gaps = { 26, -18, 29 }; @@ -136,9 +155,9 @@ std::array, 2>, TS.size()> train(const np::Array const auto [ alphas, final_classifiers ] = state_saver(title, training_gaps[0], { alphas_title, final_classifiers_title }, FORCE_REDO, SAVE_STATE, MODEL_DIR, train_viola_jones, T, X_train_feat, X_train_feat_argsort, y_train); #if __DEBUG - print("alphas"); + printf("alphas\n"); print(alphas); - print("final_classifiers"); + printf("final_classifiers\n"); print(final_classifiers); #endif models[i++] = { alphas, final_classifiers }; @@ -151,6 +170,14 @@ std::array, 2>, TS.size()> train(const np::Array return models; } +/** + * @brief Benchmark the trained classifiers on the training and testing sets. + * + * @param X_train_feat Training features. + * @param y_train Training labels. + * @param X_test_feat Testing features. + * @param y_test Testing labels. + */ void testing_and_evaluating(const std::array, 2>, TS.size()>& models, const np::Array& X_train_feat, const np::Array& y_train, const np::Array& X_test_feat, const np::Array& y_test) { const std::array testing_gaps = { 26, -19, 24, -19, 24 }; header({ "Testing", "Time spent (ns) (E)", "Formatted time spent (E)", "Time spent (ns) (T)", "Formatted time spent (T)" }, testing_gaps); @@ -201,6 +228,13 @@ void testing_and_evaluating(const std::array, 2> footer(evaluating_gaps); } +/** + * @brief Test if the each result is equals to other devices. + * + * Given ViolaJones is a fully deterministic algorithm. + * The results, regardless the device, should be the same. + * This function check this assertion. + */ void unit_test(void) { const std::chrono::system_clock::time_point unit_timestamp = perf_counter_ns(); const std::array unit_gaps = { 37, -10, -18, 29}; @@ -224,76 +258,99 @@ void unit_test(void) { formatted_row(unit_gaps, { title, "Failed", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() }); }; - for (const char* label : { "train", "test" }) { - sprintf(file_cpu, OUT_DIR "/X_%s_ii_CPU.bin", label); - sprintf(file_gpu, OUT_DIR "/X_%s_ii_GPU.bin", label); - if (fs::exists(file_cpu) && fs::exists(file_gpu)) { - const np::Array X_train_ii_cpu = load(file_cpu); - const np::Array X_train_ii_gpu = load(file_gpu); - sprintf(tmp_title, "X_%s_ii", label); - sprintf(title, "%-22s - CPU vs GPU", tmp_title); - test_fnc(title, [&X_train_ii_cpu, &X_train_ii_gpu]{ return unit_test_cpu_vs_gpu(X_train_ii_cpu, X_train_ii_gpu); }); + for (const char* const label : { "train", "test" }) { + snprintf(file_cpu, BUFFER_SIZE, OUT_DIR "/X_%s_ii_CPU.bin", label); + snprintf(file_gpu, BUFFER_SIZE, OUT_DIR "/X_%s_ii_GPU.bin", label); + if (std::filesystem::exists(file_cpu) && std::filesystem::exists(file_gpu)) { + snprintf(tmp_title, BUFFER_SIZE / 2, "X_%s_ii", label); + snprintf(title, BUFFER_SIZE, "%-22s - CPU vs GPU", tmp_title); + test_fnc(title, [&file_cpu, &file_gpu]{ + const np::Array X_train_ii_cpu = load(file_cpu); + const np::Array X_train_ii_gpu = load(file_gpu); + return unit_test_cpu_vs_gpu(X_train_ii_cpu, X_train_ii_gpu); + }); } + snprintf(file_cpu, BUFFER_SIZE, OUT_DIR "/X_%s_feat_CPU.bin", label); + snprintf(file_gpu, BUFFER_SIZE, OUT_DIR "/X_%s_feat_GPU.bin", label); + uint8_t feat = 0; char file_feat[BUFFER_SIZE] = { 0 }; - sprintf(file_feat, OUT_DIR "/X_%s_feat_CPU.bin", label); - if (fs::exists(file_feat)) { + if (std::filesystem::exists(file_cpu)) { + strncpy(file_feat, file_cpu, BUFFER_SIZE); + feat = 1; + } else if (std::filesystem::exists(file_gpu)) { + strncpy(file_feat, file_gpu, BUFFER_SIZE); + feat = 2; + } + if (feat != 0) { const np::Array X_feat = load(file_feat); - sprintf(file_gpu, OUT_DIR "/X_%s_feat_GPU.bin", label); - if (fs::exists(file_gpu)) { - const np::Array X_feat_gpu = load(file_gpu); - sprintf(tmp_title, "X_%s_feat", label); - sprintf(title, "%-22s - CPU vs GPU", tmp_title); - test_fnc(title, [&X_feat, &X_feat_gpu]{ return unit_test_cpu_vs_gpu(X_feat, X_feat_gpu); }); + snprintf(file_gpu, BUFFER_SIZE, feat == 1 ? OUT_DIR "/X_%s_feat_GPU.bin" : OUT_DIR "/X_%s_feat_CPU.bin", label); + if (std::filesystem::exists(file_gpu)) { + snprintf(tmp_title, BUFFER_SIZE / 2, "X_%s_feat", label); + snprintf(title, BUFFER_SIZE, "%-22s - CPU vs GPU", tmp_title); + test_fnc(title, [&X_feat, &file_gpu]{ + const np::Array X_feat_aux = load(file_gpu); + return unit_test_cpu_vs_gpu(X_feat, X_feat_aux); + }); } - sprintf(file_cpu, OUT_DIR "/X_%s_feat_argsort_CPU.bin", label); + snprintf(file_cpu, BUFFER_SIZE, OUT_DIR "/X_%s_feat_argsort_CPU.bin", label); np::Array X_feat_argsort_cpu; uint8_t loaded = 0; - if (fs::exists(file_cpu)) { - X_feat_argsort_cpu = std::move(load(file_cpu)); + if (std::filesystem::exists(file_cpu)) { ++loaded; - sprintf(tmp_title, "X_%s_feat_argsort", label); - sprintf(title, "%-22s - CPU argsort", tmp_title); - test_fnc(title, [&X_feat, &X_feat_argsort_cpu]{ return unit_test_argsort_2d(X_feat, X_feat_argsort_cpu); }); + snprintf(tmp_title, BUFFER_SIZE / 2, "X_%s_feat_argsort", label); + snprintf(title, BUFFER_SIZE, "%-22s - CPU argsort", tmp_title); + test_fnc(title, [&X_feat, &X_feat_argsort_cpu, &file_cpu]{ + X_feat_argsort_cpu = std::move(load(file_cpu)); + return unit_test_argsort_2d(X_feat, X_feat_argsort_cpu); + }); } - sprintf(file_gpu, OUT_DIR "/X_%s_feat_argsort_GPU.bin", label); + snprintf(file_gpu, BUFFER_SIZE, OUT_DIR "/X_%s_feat_argsort_GPU.bin", label); np::Array X_feat_argsort_gpu; - if (fs::exists(file_gpu)) { - X_feat_argsort_gpu = std::move(load(file_gpu)); + if (std::filesystem::exists(file_gpu)) { ++loaded; - sprintf(tmp_title, "X_%s_feat_argsort", label); - sprintf(title, "%-22s - GPU argsort", tmp_title); - test_fnc(title, [&X_feat, &X_feat_argsort_gpu]{ return unit_test_argsort_2d(X_feat, X_feat_argsort_gpu); }); + snprintf(tmp_title, BUFFER_SIZE / 2, "X_%s_feat_argsort", label); + snprintf(title, BUFFER_SIZE, "%-22s - GPU argsort", tmp_title); + test_fnc(title, [&X_feat, &X_feat_argsort_gpu, &file_gpu]{ + X_feat_argsort_gpu = std::move(load(file_gpu)); + return unit_test_argsort_2d(X_feat, X_feat_argsort_gpu); + }); } if (loaded == 2){ - sprintf(tmp_title, "X_%s_feat_argsort", label); - sprintf(title, "%-22s - CPU vs GPU", tmp_title); + snprintf(tmp_title, BUFFER_SIZE / 2, "X_%s_feat_argsort", label); + snprintf(title, BUFFER_SIZE, "%-22s - CPU vs GPU", tmp_title); test_fnc(title, [&X_feat_argsort_cpu, &X_feat_argsort_gpu]{ return unit_test_cpu_vs_gpu(X_feat_argsort_cpu, X_feat_argsort_gpu); }); } } } for (const size_t T : TS) - for (const char* label : { "alphas", "final_classifiers" }) { - sprintf(file_cpu, MODEL_DIR "/%s_%lu_CPU.bin", label, T); - sprintf(file_gpu, MODEL_DIR "/%s_%lu_GPU.bin", label, T); - if (fs::exists(file_cpu) && fs::exists(file_gpu)){ - const np::Array cpu = load(file_cpu); - const np::Array gpu = load(file_gpu); - sprintf(tmp_title, "%s_%ld", label, T); - sprintf(title, "%-22s - CPU vs GPU", tmp_title); - test_fnc(title, [&cpu, &gpu]{ return unit_test_cpu_vs_gpu(cpu, gpu); }); + for (const char* const label : { "alphas", "final_classifiers" }) { + snprintf(file_cpu, BUFFER_SIZE, MODEL_DIR "/%s_%lu_CPU.bin", label, T); + snprintf(file_gpu, BUFFER_SIZE, MODEL_DIR "/%s_%lu_GPU.bin", label, T); + if (std::filesystem::exists(file_cpu) && std::filesystem::exists(file_gpu)){ + snprintf(tmp_title, BUFFER_SIZE / 2, "%s_%ld", label, T); + snprintf(title, BUFFER_SIZE, "%-22s - CPU vs GPU", tmp_title); + test_fnc(title, [&file_cpu, &file_gpu]{ + const np::Array cpu = load(file_cpu); + const np::Array gpu = load(file_gpu); + return unit_test_cpu_vs_gpu(cpu, gpu); + }); } } const long long time_spent = duration_ns(perf_counter_ns() - unit_timestamp); - snprintf(title, BUFFER_SIZE, "%ld/%ld", n_success, n_total); - formatted_line(unit_gaps, "├", "┼", "─", "┤"); - formatted_row(unit_gaps, { "Unit testing summary", title, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() }); + if (n_total == 0) + formatted_row(unit_gaps, { "Unit testing summary", "No files", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() }); + else { + snprintf(title, BUFFER_SIZE, "%ld/%ld", n_success, n_total); + formatted_line(unit_gaps, "├", "┼", "─", "┤"); + formatted_row(unit_gaps, { "Unit testing summary", title, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() }); + } footer(unit_gaps); } -int main(){ +int32_t main(void){ setlocale(LC_NUMERIC, ""); // Allow proper number display const std::chrono::system_clock::time_point unit_timestamp = perf_counter_ns(); diff --git a/cpp/test.cpp b/cpp/test.cpp index 85644f3..3359e88 100644 --- a/cpp/test.cpp +++ b/cpp/test.cpp @@ -8,22 +8,22 @@ void printProgress(const float64_t& percentage) noexcept { const uint64_t val = static_cast(percentage * 100); - const int lpad = static_cast(percentage * PBWIDTH); - const int rpad = PBWIDTH - lpad; - printf("%3lu%% [%.*s%*s]\r", val, lpad, PBSTR, rpad, ""); - fflush(stdout); + const int32_t lpad = static_cast(percentage * PBWIDTH); + const int32_t rpad = PBWIDTH - lpad; + fprintf(stderr, "%3lu%% [%.*s%*s]\r", val, lpad, PBSTR, rpad, ""); + fflush(stderr); } -void clearProgress() noexcept { +void clearProgress(void) noexcept { // Progress bar width + space before + num space + space after - printf("%*c\r", PBWIDTH + 1 + 3 + 3, ' '); + fprintf(stderr, "%*c\r", PBWIDTH + 1 + 3 + 3, ' '); } template void test(const uint64_t& N) noexcept { #if __DEBUG printf("DETERMINISTIC for N=%s of %s sized %s\n", thousand_sep(N).c_str(), typeid(T).name(), format_byte_size(sizeof(T)).c_str()); - print("Estimating memory footprint at : " + format_byte_size(3 * N * sizeof(T))); + printf("Estimating memory footprint at : %s\n", format_byte_size(3 * N * sizeof(T)).c_str()); #endif T *a = new T[N], *b = new T[N], *c = new T[N]; @@ -45,7 +45,7 @@ void test(const uint64_t& N) noexcept { delete[] a, delete[] b, delete[] c; } -void test_float() noexcept { +void test_float(void) noexcept { std::cout << std::setprecision(1<<8); const uint64_t N = static_cast(1)<<28; test(N); @@ -60,4 +60,3 @@ void test_float() noexcept { //printf("%.128lf\n", static_cast(1) / 3); //printf("%.128f\n", static_cast(1) / 3); } - diff --git a/cpp/toolbox.cpp b/cpp/toolbox.cpp index 15f7d28..161410d 100644 --- a/cpp/toolbox.cpp +++ b/cpp/toolbox.cpp @@ -1,19 +1,17 @@ #include "toolbox.hpp" -#include -#include -static constexpr uint64_t u64(const double& n) noexcept { return static_cast(n); } +inline static constexpr uint64_t u64(const double& n) noexcept { return static_cast(n); } static const constexpr size_t N_TIMES = 11; -static const constexpr std::array time_formats = { "ns", "µs", "ms", "s", "m", "h", "j", "w", "M", "y", "c" }; +static const constexpr std::array time_formats = { "ns", "us", "ms", "s", "m", "h", "j", "w", "M", "y", "c" }; static const constexpr std::array time_numbers = { 1, u64(1e3), u64(1e6), u64(1e9), u64(6e10), u64(36e11), u64(864e11), u64(6048e11), u64(26784e11), u64(31536e12), u64(31536e14) }; /** * @brief Format the time in seconds in human readable format. * - * @param time Time in seconds - * @return std::string The formatted human readable string. + * @param time number of seconds + * @return The formatted human readable string. */ std::string format_time(uint64_t time) noexcept { if (time == 0) @@ -21,8 +19,8 @@ std::string format_time(uint64_t time) noexcept { std::string s = ""; uint64_t res; - for (int i = N_TIMES - 1; i >= 3; --i) { - const uint64_t time_number = time_numbers[i] / 1e9; // Converting nanosecond timestamp to second + for (int32_t i = N_TIMES - 1; i >= 3; --i) { + const uint64_t time_number = time_numbers[i] / u64(1e9); // Converting nanosecond timestamp to second if (time >= time_number) { res = time / time_number; time %= time_number; @@ -30,8 +28,8 @@ std::string format_time(uint64_t time) noexcept { } } - if (s.back() == ' ') - s.pop_back(); + // Remove trailing character + s.pop_back(); return s; } @@ -48,7 +46,7 @@ std::string format_time_ns(uint64_t time) noexcept { std::string s = ""; uint64_t res; - for (int i = N_TIMES - 1; i >= 0; --i) { + for (int32_t i = N_TIMES - 1; i >= 0; --i) { if (time >= time_numbers[i]) { res = time / time_numbers[i]; time %= time_numbers[i]; @@ -56,8 +54,8 @@ std::string format_time_ns(uint64_t time) noexcept { } } - if (s.back() == ' ') - s.pop_back(); + // Remove trailing character + s.pop_back(); return s; } @@ -71,7 +69,7 @@ static const constexpr uint64_t total_bytes = u64(1)<<(10 * (N_BYTES - 1)); * See more : https://en.wikipedia.org/wiki/JEDEC_memory_standards * * @param bytes Number of bytes - * @return std::string JEDEC compliant formatted number of bytes + * @return JEDEC compliant formatted number of bytes */ std::string format_byte_size(uint64_t bytes) noexcept { if (bytes == 0) @@ -95,6 +93,13 @@ std::string format_byte_size(uint64_t bytes) noexcept { return s; } +/** + * @brief Format a number with a separator (i.e. 1000 as 1,000) + * + * @param k number to format + * @param separator used between each thouand + * @return Formatted number + */ std::string thousand_sep(uint64_t k, const char& separator) noexcept { const std::string n = std::to_string(k); const uint64_t st_size = n.length() + (n.length() - 1) / 3; @@ -110,5 +115,13 @@ std::string thousand_sep(uint64_t k, const char& separator) noexcept { } return s; -} + //uint64_t len = n.length(), dlen = 3; + + //while (len > dlen) { + // n.insert(len - dlen, 1, separator); + // dlen += 4; + // len += 1; + //} + //return n; +} diff --git a/cpp/toolbox_unit_test.cpp b/cpp/toolbox_unit_test.cpp index df35f81..5ae3a77 100644 --- a/cpp/toolbox_unit_test.cpp +++ b/cpp/toolbox_unit_test.cpp @@ -3,7 +3,7 @@ #include template -void Assert(const char* name, const T& expected, const T& result) noexcept { +void Assert(const char* const name, const T& expected, const T& result) noexcept { if(expected != result){ std::cerr << "For test named " << name << " Expected '" << expected << "' but got '" << result << "' instead\n"; assert(false); @@ -11,17 +11,17 @@ void Assert(const char* name, const T& expected, const T& result) noexcept { } void format_byte_size_test(void) noexcept { - Assert("format_byte_size null", std::string("0B"), format_byte_size(static_cast(0))); - Assert("format_byte_size byte", std::string("1B"), format_byte_size(static_cast(1))); - Assert("format_byte_size kilobyte", std::string("1KB"), format_byte_size(static_cast(1)<<10)); - Assert("format_byte_size megabyte", std::string("1MB"), format_byte_size(static_cast(1)<<20)); - Assert("format_byte_size gigabyte", std::string("1GB"), format_byte_size(static_cast(1)<<30)); - Assert("format_byte_size terabyte", std::string("1TB"), format_byte_size(static_cast(1)<<40)); - Assert("format_byte_size petabyte", std::string("1PB"), format_byte_size(static_cast(1)<<50)); - Assert("format_byte_size exabyte", std::string("1EB"), format_byte_size(static_cast(1)<<60)); + Assert("format_byte_size null", std::string("0B"), format_byte_size(static_cast(0))); + Assert("format_byte_size byte", std::string("1B"), format_byte_size(static_cast(1))); + Assert("format_byte_size kilobyte", std::string("1KB"), format_byte_size(static_cast(1)<<10)); + Assert("format_byte_size megabyte", std::string("1MB"), format_byte_size(static_cast(1)<<20)); + Assert("format_byte_size gigabyte", std::string("1GB"), format_byte_size(static_cast(1)<<30)); + Assert("format_byte_size terabyte", std::string("1TB"), format_byte_size(static_cast(1)<<40)); + Assert("format_byte_size petabyte", std::string("1PB"), format_byte_size(static_cast(1)<<50)); + Assert("format_byte_size exabyte", std::string("1EB"), format_byte_size(static_cast(1)<<60)); // Unsupported due to number of byte bigger than currently supported by ISO c++ - //Assert("format_byte_size zettabyte", std::string("1ZB"), format_byte_size(static_cast(1)<<70)); - //Assert("format_byte_size yottabyte", std::string("1YB"), format_byte_size(static_cast(1)<<80)); + //Assert("format_byte_size zettabyte", std::string("1ZB"), format_byte_size(static_cast(1)<<70)); + //Assert("format_byte_size yottabyte", std::string("1YB"), format_byte_size(static_cast(1)<<80)); // uint64_t_MAX == 2**64 == 18446744073709551615I64u == -1 Assert("format_byte_size max", std::string("15EB 1023PB 1023TB 1023GB 1023MB 1023KB 1023B"), format_byte_size(static_cast(-1))); } @@ -82,62 +82,62 @@ void format_time_test(void) noexcept { void format_time_ns_test(void) noexcept { // https://en.wikipedia.org/wiki/Unit_of_time - Assert("format_time_ns null", std::string("0ns"), format_time_ns(static_cast(0))); - Assert("format_time_ns nanosecond", std::string("1ns"), format_time_ns(static_cast(1))); - Assert("format_time_ns shake", std::string("10ns"), format_time_ns(static_cast(10))); - Assert("format_time_ns microsecond", std::string("1µs"), format_time_ns(static_cast(1e3))); - Assert("format_time_ns millisecond", std::string("1ms"), format_time_ns(static_cast(1e6))); - Assert("format_time_ns centisecond", std::string("10ms"), format_time_ns(static_cast(1e7))); - Assert("format_time_ns decisecond", std::string("100ms"), format_time_ns(static_cast(1e8))); - Assert("format_time_ns second", std::string("1s"), format_time_ns(static_cast(1e9))); - Assert("format_time_ns decasecond", std::string("10s"), format_time_ns(static_cast(1e10))); - Assert("format_time_ns minute", std::string("1m"), format_time_ns(static_cast(6e10))); - Assert("format_time_ns milliday", std::string("1m 26s 400ms"), format_time_ns(static_cast(864e8))); - Assert("format_time_ns hectosecond", std::string("1m 40s"), format_time_ns(static_cast(1e11))); - Assert("format_time_ns kilosecond", std::string("16m 40s"), format_time_ns(static_cast(1e12))); - Assert("format_time_ns hour", std::string("1h"), format_time_ns(static_cast(36e11))); - Assert("format_time_ns day", std::string("1j"), format_time_ns(static_cast(864e11))); - Assert("format_time_ns week/sennight", std::string("1w"), format_time_ns(static_cast(6048e11))); - Assert("format_time_ns megasecond", std::string("1w 4j 13h 46m 40s"), format_time_ns(static_cast(1e15))); - Assert("format_time_ns fortnight", std::string("2w"), format_time_ns(static_cast(12096e11))); - Assert("format_time_ns lunar month (draconitic)", std::string("3w 6j 5h 5m 35s 800ms"), format_time_ns(static_cast(23511358e8))); - Assert("format_time_ns lunar month (tropical)", std::string("3w 6j 7h 43m 4s 700ms"), format_time_ns(static_cast(23605847e8))); - Assert("format_time_ns lunar month (sidereal)", std::string("3w 6j 7h 43m 11s 600ms"), format_time_ns(static_cast(23605916e8))); - Assert("format_time_ns lunar month (anomalistic)", std::string("3w 6j 13h 18m 33s 200ms"), format_time_ns(static_cast(23807132e8))); - Assert("format_time_ns lunar month (synodic)", std::string("4w 1j 12h 44m 2s 900ms"), format_time_ns(static_cast(25514429e8))); - Assert("format_time_ns month", std::string("1M"), format_time_ns(static_cast(26784e11))); - Assert("format_time_ns quarantine", std::string("1M 1w 2j"), format_time_ns(static_cast(3456e12))); - Assert("format_time_ns semester", std::string("4M 2j"), format_time_ns(static_cast(108864e11))); - Assert("format_time_ns lunar year", std::string("11M 1w 6j 8h 52m 48s"), format_time_ns(static_cast(30617568e9))); - Assert("format_time_ns year", std::string("1y"), format_time_ns(static_cast(31536e12))); - Assert("format_time_ns tropical year", std::string("1y 5h 48m 45s 216ms"), format_time_ns(static_cast(31556925216e6))); - Assert("format_time_ns gregorian year", std::string("1y 5h 49m 12s"), format_time_ns(static_cast(31556952e9))); - Assert("format_time_ns sidereal year", std::string("1y 6h 9m 9s 763ms 545µs 600ns"), format_time_ns(static_cast(315581497635456e2))); - Assert("format_time_ns leap year", std::string("1y 1j"), format_time_ns(static_cast(316224e11))); - Assert("format_time_ns olympiad", std::string("4y"), format_time_ns(static_cast(126144e12))); - Assert("format_time_ns lusturm", std::string("5y"), format_time_ns(static_cast(15768e13))); - Assert("format_time_ns decade", std::string("10y"), format_time_ns(static_cast(31536e13))); - Assert("format_time_ns indiction", std::string("15y"), format_time_ns(static_cast(47304e13))); - Assert("format_time_ns score", std::string("20y"), format_time_ns(static_cast(63072e13))); - Assert("format_time_ns gigasecond", std::string("31y 8M 1w 4j 1h 46m 40s"), format_time_ns(static_cast(1e18))); - Assert("format_time_ns jubilee", std::string("50y"), format_time_ns(static_cast(15768e14))); - Assert("format_time_ns century", std::string("1c"), format_time_ns(static_cast(31536e14))); + Assert("format_time_ns null", std::string("0ns"), format_time_ns(static_cast(0))); + Assert("format_time_ns nanosecond", std::string("1ns"), format_time_ns(static_cast(1))); + Assert("format_time_ns shake", std::string("10ns"), format_time_ns(static_cast(10))); + Assert("format_time_ns microsecond", std::string("1us"), format_time_ns(static_cast(1e3))); + Assert("format_time_ns millisecond", std::string("1ms"), format_time_ns(static_cast(1e6))); + Assert("format_time_ns centisecond", std::string("10ms"), format_time_ns(static_cast(1e7))); + Assert("format_time_ns decisecond", std::string("100ms"), format_time_ns(static_cast(1e8))); + Assert("format_time_ns second", std::string("1s"), format_time_ns(static_cast(1e9))); + Assert("format_time_ns decasecond", std::string("10s"), format_time_ns(static_cast(1e10))); + Assert("format_time_ns minute", std::string("1m"), format_time_ns(static_cast(6e10))); + Assert("format_time_ns milliday", std::string("1m 26s 400ms"), format_time_ns(static_cast(864e8))); + Assert("format_time_ns hectosecond", std::string("1m 40s"), format_time_ns(static_cast(1e11))); + Assert("format_time_ns kilosecond", std::string("16m 40s"), format_time_ns(static_cast(1e12))); + Assert("format_time_ns hour", std::string("1h"), format_time_ns(static_cast(36e11))); + Assert("format_time_ns day", std::string("1j"), format_time_ns(static_cast(864e11))); + Assert("format_time_ns week/sennight", std::string("1w"), format_time_ns(static_cast(6048e11))); + Assert("format_time_ns megasecond", std::string("1w 4j 13h 46m 40s"), format_time_ns(static_cast(1e15))); + Assert("format_time_ns fortnight", std::string("2w"), format_time_ns(static_cast(12096e11))); + Assert("format_time_ns lunar month (draconitic)", std::string("3w 6j 5h 5m 35s 800ms"), format_time_ns(static_cast(23511358e8))); + Assert("format_time_ns lunar month (tropical)", std::string("3w 6j 7h 43m 4s 700ms"), format_time_ns(static_cast(23605847e8))); + Assert("format_time_ns lunar month (sidereal)", std::string("3w 6j 7h 43m 11s 600ms"), format_time_ns(static_cast(23605916e8))); + Assert("format_time_ns lunar month (anomalistic)", std::string("3w 6j 13h 18m 33s 200ms"), format_time_ns(static_cast(23807132e8))); + Assert("format_time_ns lunar month (synodic)", std::string("4w 1j 12h 44m 2s 900ms"), format_time_ns(static_cast(25514429e8))); + Assert("format_time_ns month", std::string("1M"), format_time_ns(static_cast(26784e11))); + Assert("format_time_ns quarantine", std::string("1M 1w 2j"), format_time_ns(static_cast(3456e12))); + Assert("format_time_ns semester", std::string("4M 2j"), format_time_ns(static_cast(108864e11))); + Assert("format_time_ns lunar year", std::string("11M 1w 6j 8h 52m 48s"), format_time_ns(static_cast(30617568e9))); + Assert("format_time_ns year", std::string("1y"), format_time_ns(static_cast(31536e12))); + Assert("format_time_ns tropical year", std::string("1y 5h 48m 45s 216ms"), format_time_ns(static_cast(31556925216e6))); + Assert("format_time_ns gregorian year", std::string("1y 5h 49m 12s"), format_time_ns(static_cast(31556952e9))); + Assert("format_time_ns sidereal year", std::string("1y 6h 9m 9s 763ms 545us 600ns"), format_time_ns(static_cast(315581497635456e2))); + Assert("format_time_ns leap year", std::string("1y 1j"), format_time_ns(static_cast(316224e11))); + Assert("format_time_ns olympiad", std::string("4y"), format_time_ns(static_cast(126144e12))); + Assert("format_time_ns lusturm", std::string("5y"), format_time_ns(static_cast(15768e13))); + Assert("format_time_ns decade", std::string("10y"), format_time_ns(static_cast(31536e13))); + Assert("format_time_ns indiction", std::string("15y"), format_time_ns(static_cast(47304e13))); + Assert("format_time_ns score", std::string("20y"), format_time_ns(static_cast(63072e13))); + Assert("format_time_ns gigasecond", std::string("31y 8M 1w 4j 1h 46m 40s"), format_time_ns(static_cast(1e18))); + Assert("format_time_ns jubilee", std::string("50y"), format_time_ns(static_cast(15768e14))); + Assert("format_time_ns century", std::string("1c"), format_time_ns(static_cast(31536e14))); // Cannot use number bigger than currently supported ISO C++ - //Assert("format_time_ns millennium", std::string("10c"), format_time_ns(static_cast(31536e15))); - //Assert("format_time_ns age", std::string("257c 72y"), format_time_ns(static_cast(812745792e12))); - //Assert("format_time_ns terasecond", std::string("3170c 97y 10M 3w 4j 17h 46m 40s"), format_time_ns(static_cast(1e22))); - //Assert("format_time_ns megaannum", std::string("10000c"), format_time_ns(static_cast(31536e18))); - //Assert("format_time_ns petasecond", std::string("317097c 91y 11M 2w 4j 1h 46m 40s"), format_time_ns(static_cast(1e24))); - //Assert("format_time_ns galactic year", std::string("2300000c"), format_time_ns(static_cast(725328e19))); - //Assert("format_time_ns eon", std::string("10000000c"), format_time_ns(static_cast(31536e21))); - //Assert("format_time_ns kalpa", std::string("43200000c"), format_time_ns(static_cast(13623552e19))); - //Assert("format_time_ns exasecond", std::string("317097919c 83y 9M 1h 46m 40s"), format_time_ns(static_cast(1e27))); - //Assert("format_time_ns zettasecond", std::string(""), format_time_ns(static_cast(1e30))); - //Assert("format_time_ns yottasecond", std::string(""), format_time_ns(static_cast(1e33))); - //Assert("format_time_ns ronnasecond", std::string(""), format_time_ns(static_cast(1e36))); - //Assert("format_time_ns quettasecond", std::string(""), format_time_ns(static_cast(1e39))); + //Assert("format_time_ns millennium", std::string("10c"), format_time_ns(static_cast(31536e15))); + //Assert("format_time_ns age", std::string("257c 72y"), format_time_ns(static_cast(812745792e12))); + //Assert("format_time_ns terasecond", std::string("3170c 97y 10M 3w 4j 17h 46m 40s"), format_time_ns(static_cast(1e22))); + //Assert("format_time_ns megaannum", std::string("10000c"), format_time_ns(static_cast(31536e18))); + //Assert("format_time_ns petasecond", std::string("317097c 91y 11M 2w 4j 1h 46m 40s"), format_time_ns(static_cast(1e24))); + //Assert("format_time_ns galactic year", std::string("2300000c"), format_time_ns(static_cast(725328e19))); + //Assert("format_time_ns eon", std::string("10000000c"), format_time_ns(static_cast(31536e21))); + //Assert("format_time_ns kalpa", std::string("43200000c"), format_time_ns(static_cast(13623552e19))); + //Assert("format_time_ns exasecond", std::string("317097919c 83y 9M 1h 46m 40s"), format_time_ns(static_cast(1e27))); + //Assert("format_time_ns zettasecond", std::string(""), format_time_ns(static_cast(1e30))); + //Assert("format_time_ns yottasecond", std::string(""), format_time_ns(static_cast(1e33))); + //Assert("format_time_ns ronnasecond", std::string(""), format_time_ns(static_cast(1e36))); + //Assert("format_time_ns quettasecond", std::string(""), format_time_ns(static_cast(1e39))); // uint64_t_MAX == 2**64 == 18446744073709551615I64u == -1 - Assert("format_time_ns max", std::string("5c 84y 11M 2j 23h 34m 33s 709ms 551µs 615ns"), format_time_ns(static_cast(-1))); + Assert("format_time_ns max", std::string("5c 84y 11M 2j 23h 34m 33s 709ms 551us 615ns"), format_time_ns(static_cast(-1))); } void thousand_sep_test(void) noexcept { @@ -182,4 +182,3 @@ void thousand_sep_test(void) noexcept { // uint64_t_MAX == 2**64 == 18446744073709551615I64u == -1 Assert("thousand_sep max", std::string("18,446,744,073,709,551,615"), thousand_sep(static_cast(-1))); } -