From bd3eb5278a2cc18a40f42ab1da38398381a99fb6 Mon Sep 17 00:00:00 2001 From: 30hours Date: Mon, 20 Nov 2023 23:05:01 +1030 Subject: [PATCH] Add timing class and API --- CMakeLists.txt | 2 + api/server.js | 24 +++++++-- config/config.yml | 2 + config/radar4.yml | 4 +- src/blah2.cpp | 94 +++++++++++++++++++++++++---------- src/data/meta/Timing.cpp | 103 +++++++++++++++++++++++++++++++++++++++ src/data/meta/Timing.h | 58 ++++++++++++++++++++++ 7 files changed, 257 insertions(+), 30 deletions(-) create mode 100644 src/data/meta/Timing.cpp create mode 100644 src/data/meta/Timing.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b2b54f4..5ac48c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable(blah2 ${PROJECT_SOURCE_DIR}/data/IqData.cpp ${PROJECT_SOURCE_DIR}/data/Map.cpp ${PROJECT_SOURCE_DIR}/data/Detection.cpp + ${PROJECT_SOURCE_DIR}/data/meta/Timing.cpp ) add_library(ryml ${PROJECT_LIB_DIR}/rapidyaml-0.5.0/ryml-0.5.0.hpp) @@ -65,3 +66,4 @@ include_directories("${PROJECT_SOURCE_DIR}/process/ambiguity/") include_directories("${PROJECT_SOURCE_DIR}/process/clutter/") include_directories("${PROJECT_SOURCE_DIR}/process/detection/") include_directories("${PROJECT_SOURCE_DIR}/data/") +include_directories("${PROJECT_SOURCE_DIR}/data/meta/") diff --git a/api/server.js b/api/server.js index 8cb4e29..991a6e9 100644 --- a/api/server.js +++ b/api/server.js @@ -11,6 +11,7 @@ const HOST = '0.0.0.0'; var map = ''; var detection = ''; var timestamp = ''; +var timing = ''; var data = ''; var capture = false; @@ -36,6 +37,9 @@ app.get('/detection', (req, res) => { app.get('/timestamp', (req, res) => { res.send(timestamp); }); +app.get('/timing', (req, res) => { + res.send(timing); +}); app.get('/maxhold', (req, res) => { res.send(maxhold.get_data()); }); @@ -59,7 +63,6 @@ const server_map = net.createServer((socket)=>{ data = data + msg.toString(); if (data.slice(-1) === "}") { - console.log('EOF'); map = data; data = ''; } @@ -77,7 +80,6 @@ const server_detection = net.createServer((socket)=>{ data = data + msg.toString(); if (data.slice(-1) === "}") { - console.log('EOF'); detection = data; data = ''; } @@ -93,7 +95,6 @@ const server_timestamp = net.createServer((socket)=>{ socket.write("Hello From Server!") socket.on("data",(msg)=>{ data = data + msg.toString(); - console.log('EOF'); timestamp = data; data = ''; }); @@ -102,3 +103,20 @@ const server_timestamp = net.createServer((socket)=>{ }) }); server_timestamp.listen(4000); + +// tcp listener timing +const server_timing = net.createServer((socket)=>{ + socket.write("Hello From Server!") + socket.on("data",(msg)=>{ + data = data + msg.toString(); + if (data.slice(-1) === "}") + { + timing = data; + data = ''; + } + }); + socket.on("close",()=>{ + console.log("Connection closed."); + }) +}); +server_timing.listen(4001); diff --git a/config/config.yml b/config/config.yml index 5b495af..e1806ee 100644 --- a/config/config.yml +++ b/config/config.yml @@ -32,9 +32,11 @@ network: map: 3001 detect: 3002 timestamp: 4000 + timing: 4001 save: iq: true map: true detect: false + timing: false path: "/opt/blah2/" diff --git a/config/radar4.yml b/config/radar4.yml index 5473f12..b01bc03 100644 --- a/config/radar4.yml +++ b/config/radar4.yml @@ -9,7 +9,7 @@ capture: process: data: - cpi: 1 + cpi: 0.5 buffer: 1.5 overlap: 0 ambiguity: @@ -32,9 +32,11 @@ network: map: 3001 detection: 3002 timestamp: 4000 + timing: 4001 save: iq: true map: false detection: false + timing: false path: "/blah2/save/" diff --git a/src/blah2.cpp b/src/blah2.cpp index d221608..ee47e83 100644 --- a/src/blah2.cpp +++ b/src/blah2.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,8 @@ void signal_callback_handler(int signum); void getopt_print_help(); std::string getopt_process(int argc, char **argv); std::string ryml_get_file(const char *filename); +uint64_t current_time_ms(); +uint64_t current_time_us(); int main(int argc, char **argv) { @@ -93,28 +96,34 @@ int main(int argc, char **argv) fftw_plan_with_nthreads(4); // setup socket - uint16_t port_map, port_detection, port_timestamp; + uint16_t port_map, port_detection, port_timestamp, port_timing; std::string ip; tree["network"]["ports"]["map"] >> port_map; tree["network"]["ports"]["detection"] >> port_detection; tree["network"]["ports"]["timestamp"] >> port_timestamp; + tree["network"]["ports"]["timing"] >> port_timing; tree["network"]["ip"] >> ip; asio::io_service io_service; asio::ip::tcp::socket socket_map(io_service); asio::ip::tcp::socket socket_detection(io_service); asio::ip::tcp::socket socket_timestamp(io_service); + asio::ip::tcp::socket socket_timing(io_service); asio::ip::tcp::endpoint endpoint_map; asio::ip::tcp::endpoint endpoint_detection; asio::ip::tcp::endpoint endpoint_timestamp; + asio::ip::tcp::endpoint endpoint_timing; endpoint_map = asio::ip::tcp::endpoint( asio::ip::address::from_string(ip), port_map); endpoint_detection = asio::ip::tcp::endpoint( asio::ip::address::from_string(ip), port_detection); endpoint_timestamp = asio::ip::tcp::endpoint( asio::ip::address::from_string(ip), port_timestamp); + endpoint_timing = asio::ip::tcp::endpoint( + asio::ip::address::from_string(ip), port_timing); socket_map.connect(endpoint_map); socket_detection.connect(endpoint_detection); socket_timestamp.connect(endpoint_timestamp); + socket_timing.connect(endpoint_timing); asio::error_code err; std::string subdata; uint32_t MTU = 1024; @@ -160,13 +169,20 @@ int main(int argc, char **argv) saveMapPath = savePath + ".map"; } + // setup output timing + uint64_t tStart = current_time_ms(); + Timing *timing = new Timing(tStart); + std::vector timing_name; + std::vector timing_time; + std::string jsonTiming; + // run process std::thread t2([&]{ while (true) { if ((buffer1->get_length() > nSamples) && (buffer2->get_length() > nSamples)) { - auto t0 = std::chrono::high_resolution_clock::now(); + uint64_t t0 = current_time_us(); // extract data from buffer buffer1->lock(); @@ -178,30 +194,34 @@ int main(int argc, char **argv) } buffer1->unlock(); buffer2->unlock(); - auto t1 = std::chrono::high_resolution_clock::now(); - double delta_t1 = std::chrono::duration(t1-t0).count(); - std::cout << "Extract data from buffer (ms): " << delta_t1 << std::endl; + uint64_t t1 = current_time_us(); + double delta_t1 = (double)(t1-t0) / 1000; + timing_name.push_back("extract_buffer"); + timing_time.push_back(delta_t1); // clutter filter if (!filter->process(x, y)) { continue; } - auto t2 = std::chrono::high_resolution_clock::now(); - double delta_t2 = std::chrono::duration(t2-t1).count(); - std::cout << "Clutter filter (ms): " << delta_t2 << std::endl; + uint64_t t2 = current_time_us(); + double delta_t2 = (double)(t2-t1) / 1000; + timing_name.push_back("clutter_filter"); + timing_time.push_back(delta_t2); // ambiguity process map = ambiguity->process(x, y); - auto t3 = std::chrono::high_resolution_clock::now(); - double delta_t3 = std::chrono::duration(t3-t2).count(); - std::cout << "Ambiguity processing (ms): " << delta_t3 << std::endl; + uint64_t t3 = current_time_us(); + double delta_t3 = (double)(t3-t2) / 1000; + timing_name.push_back("ambiguity_processing"); + timing_time.push_back(delta_t3); // detection process // detection = cfarDetector1D->process(map); - auto t4 = std::chrono::high_resolution_clock::now(); - double delta_t4 = std::chrono::duration(t4-t3).count(); - std::cout << "Detection processing (ms): " << delta_t4 << std::endl; + uint64_t t4 = current_time_us(); + double delta_t4 = (double)(t4-t3) / 1000; + timing_name.push_back("detector"); + timing_time.push_back(delta_t4); // output map data map->set_metrics(); @@ -216,9 +236,6 @@ int main(int argc, char **argv) subdata = mapJson.substr(i * MTU, MTU); socket_map.write_some(asio::buffer(subdata, subdata.size()), err); } - auto t5 = std::chrono::high_resolution_clock::now(); - double delta_t5 = std::chrono::duration(t5-t4).count(); - std::cout << "Output map data (ms): " << delta_t5 << std::endl; // output detection data // detectionJson = detection->to_json(); @@ -228,19 +245,30 @@ int main(int argc, char **argv) // socket_detection.write_some(asio::buffer(subdata, subdata.size()), err); // } // delete detection; - auto t6 = std::chrono::high_resolution_clock::now(); - double delta_t6 = std::chrono::duration(t6-t5).count(); - std::cout << "Output detection data (ms): " << delta_t6 << std::endl; + + // output radar data timer + uint64_t t5 = current_time_us(); + double delta_t5 = (double)(t5-t4) / 1000; + timing_name.push_back("output_radar_data"); + timing_time.push_back(delta_t5); - auto t7 = std::chrono::high_resolution_clock::now(); - double delta_t7 = std::chrono::duration(t7-t0).count(); - std::cout << "CPI time (ms): " << delta_t7 << std::endl; + // cpi timer + uint64_t t6 = current_time_us(); + double delta_t6 = (double)(t6-t0) / 1000; + timing_name.push_back("cpi"); + timing_time.push_back(delta_t6); + std::cout << "CPI time (ms): " << delta_t6 << std::endl; // output CPI timestamp for updating data - auto t0_duration = t0.time_since_epoch(); - auto t0_ms = std::chrono::duration_cast(t0_duration).count(); - std::string t0_string = std::to_string(t0_ms); + std::string t0_string = std::to_string(t0); socket_timestamp.write_some(asio::buffer(t0_string, 100), err); + + // output timing data + timing->update(t0/1000, timing_time, timing_name); + jsonTiming = timing->to_json(); + socket_timing.write_some(asio::buffer(jsonTiming, 1500), err); + timing_time.clear(); + timing_name.clear(); } } }); @@ -325,4 +353,18 @@ std::string ryml_get_file(const char *filename) std::ostringstream contents; contents << in.rdbuf(); return contents.str(); +} + +uint64_t current_time_ms() +{ + // current time in POSIX ms + return std::chrono::duration_cast + (std::chrono::system_clock::now().time_since_epoch()).count(); +} + +uint64_t current_time_us() +{ + // current time in POSIX us + return std::chrono::duration_cast + (std::chrono::system_clock::now().time_since_epoch()).count(); } \ No newline at end of file diff --git a/src/data/meta/Timing.cpp b/src/data/meta/Timing.cpp new file mode 100644 index 0000000..600de46 --- /dev/null +++ b/src/data/meta/Timing.cpp @@ -0,0 +1,103 @@ +#include "Timing.h" +#include +#include + +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/filewritestream.h" + +// constructor +Timing::Timing(uint64_t _tStart) +{ + tStart = _tStart; + n = 0; +} + +void Timing::update(uint64_t _tNow, std::vector _time, std::vector _name) +{ + n = n + 1; + tNow = _tNow; + time = _time; + name = _name; + uptime = _tNow-tStart; +} + +std::string Timing::to_json() +{ + rapidjson::Document document; + document.SetObject(); + rapidjson::Document::AllocatorType &allocator = document.GetAllocator(); + + document.AddMember("timestamp", tNow, allocator); + document.AddMember("nCpi", n, allocator); + document.AddMember("uptime", uptime, allocator); + rapidjson::Value name_value; + for (int i = 0; i < time.size(); i++) + { + name_value = rapidjson::StringRef(name[i].c_str()); + document.AddMember(name_value, time[i], allocator); + } + + rapidjson::StringBuffer strbuf; + rapidjson::Writer writer(strbuf); + writer.SetMaxDecimalPlaces(2); + document.Accept(writer); + + return strbuf.GetString(); +} + +bool Timing::save(std::string _json, std::string filename) +{ + using namespace rapidjson; + + rapidjson::Document document; + + // create file if it doesn't exist + if (FILE *fp = fopen(filename.c_str(), "r"); !fp) + { + if (fp = fopen(filename.c_str(), "w"); !fp) + return false; + fputs("[]", fp); + fclose(fp); + } + + // add the document to the file + if (FILE *fp = fopen(filename.c_str(), "rb+"); fp) + { + // check if first is [ + std::fseek(fp, 0, SEEK_SET); + if (getc(fp) != '[') + { + std::fclose(fp); + return false; + } + + // is array empty? + bool isEmpty = false; + if (getc(fp) == ']') + isEmpty = true; + + // check if last is ] + std::fseek(fp, -1, SEEK_END); + if (getc(fp) != ']') + { + std::fclose(fp); + return false; + } + + // replace ] by , + fseek(fp, -1, SEEK_END); + if (!isEmpty) + fputc(',', fp); + + // add json element + fwrite(_json.c_str(), sizeof(char), _json.length(), fp); + + // close the array + std::fputc(']', fp); + fclose(fp); + return true; + } + return false; +} diff --git a/src/data/meta/Timing.h b/src/data/meta/Timing.h new file mode 100644 index 0000000..6a60953 --- /dev/null +++ b/src/data/meta/Timing.h @@ -0,0 +1,58 @@ +/// @file Timing.h +/// @class Timing +/// @brief A class to store timing statistics. +/// @author 30hours + +#ifndef TIMING_H +#define TIMING_H + +#include +#include +#include + +class Timing +{ +private: + /// @brief Start time (POSIX ms). + uint64_t tStart; + + /// @brief Current time (POSIX ms). + uint64_t tNow; + + /// @brief Number of CPI's. + uint64_t n; + + /// @brief Time since first CPI (ms). + uint64_t uptime; + + /// @brief Time differences (ms). + std::vector time; + + /// @brief Names of time differences. + std::vector name; + +public: + /// @brief Constructor. + /// @param tStart Start time (POSIX ms). + /// @return The object. + Timing(uint64_t tStart); + + /// @brief Update the time differences and names. + /// @param tNow Current time (POSIX ms). + /// @param time Vector of time differences (ms). + /// @param name Vector of time difference names. + /// @return Void. + void update(uint64_t tNow, std::vector time, std::vector name); + + /// @brief Generate JSON of the map and metadata. + /// @return JSON string. + std::string to_json(); + + /// @brief Append the map to a save file. + /// @param json JSON string of map and metadata. + /// @param path Path of file to save. + /// @return True is save is successful. + bool save(std::string json, std::string path); +}; + +#endif