diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 53cbedf13..3c6449050 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,50 +1,99 @@ # Description -Thank you for opening a PR. Please summarize the changes in 1 or 2 sentences. +Thank you for opening a PR! Please summarize the changes in 1–2 sentences. ## Type of change -Delete options that are not relevant. - - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Breaking change (fix or feature that causes existing functionality to not work as expected) +- [ ] Other (please describe): + +## Detailed Summary + +Provide the motivation, context, and links to any related issues, PRs, or documentation: + +- Motivation: Why is this change necessary? +- Context: How does it fit into wavemap's functionality? +- Related issues/PRs: Fixes # (issue) / Links to other PRs + +## API Changes + +List any changes to wavemap's APIs to help users update their code. Write "None" if there are no changes. + +### C++ API: + +* + +### Python API: + +* -## Detailed summary +### ROS1 Interface: -Please describe the motivation, context and a link to related issues (if appropriate). List any dependencies that are required for this change. +* -Feel free to summarize the changes as a list of bullet points. +## Review Notes -Fixes # (issue) +Is there anything specific the reviewers should focus on, or are there unresolved questions? Mention them here. # Testing -If possible, verify that the changes produce the desired results by extending the unit tests. If you would like us to help you with this, feel free to open the pull request already and let us know. +### Automated Tests -If manual tests were performed to verify these changes, please describe them here and provide instructions to reproduce them. Please also list any relevant details for your test configuration below. +Have you added or modified unit tests to verify these changes? If not, let us know if you'd like assistance. -If the changes are performance related, this is a good place to list the metrics that were used and the improvements that have been achieved. +### Manual Tests -**System information (please complete if relevant):** -- CPU: [e.g. Intel i9-9900K] -- GPU: [e.g. Nvidia RTX 2080Ti] # Only for visualization-related issues -- RAM: [e.g. 32GB] -- OS: [e.g. Ubuntu 20.04] -- Installation: [e.g., Native (ROS with catkin); or Docker] +If manual tests were performed to verify these changes, describe them here and include instructions to reproduce them. +Describe test configurations where applicable. -**Runtime information (please complete if relevant):** -- Launch file: [e.g. Link to the launch file you used] -- Config file: [e.g. Link to the config file you used] -- Dataset name [e.g. Newer College Cloister sequence] # For public datasets -- Custom setup: # For online use or personal datasets - - Depth sensor: [e.g. Livox MID360 LiDAR] - - Pose source: [e.g. Odometry from FastLIO2] +**System information (optional):** -# Checklist: +- CPU: [e.g., Intel i9-9900K] +- GPU: [e.g., Nvidia RTX 2080Ti] +- RAM: [e.g., 32GB] +- OS: [e.g., Ubuntu 20.04] +- API: [e.g., C++, Python, ROS1] +- Installation: [e.g., pre-built Docker, local CMake, Pip, catkin] + +**Runtime information (optional):** + +- Launch file: [e.g., Link or GitHub Gist] +- Config file: [e.g., Link or GitHub Gist] +- Dataset name (if public): [e.g., Newer College Cloister] +- Custom setup (for private datasets, or live usage): + - Depth sensor: [e.g., Livox MID360 LiDAR] + - Pose source: [e.g., Odometry from FastLIO2] + +For performance or accuracy-related changes, include the above system and runtime information and describe: + +- **Performance (optional)** + - Measured operation: [e.g. serializing the map, performing 1M queries, processing dataset X] + - Metrics [e.g., CPU time, wall time, total RAM usage] +- **Accuracy (optional)** + - Metrics: [e.g., AUC, accuracy, recall] +- **Summary of changes** + - What metrics improved and by how much? + - Did any metrics worsen? + +### Benchmarks (To be completed by maintainers) + +We will rerun wavemap's benchmarks and report the results here to validate there are no general performance/accuracy regressions. + +# Checklist + +General - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas -- [ ] I have made corresponding changes to the documentation +- [ ] I have added or updated tests as required - [ ] Any required changes in dependencies have been committed and pushed + +Documentation (where applicable) + +- [ ] I have updated the installation instructions (in docs/pages/installation) +- [ ] I have updated the code's inline API documentation (e.g., docstrings) +- [ ] I have updated the parameter documentation (in docs/pages/parameters) +- [ ] I have updated/extended the tutorials (in docs/pages/tutorials) diff --git a/examples/cpp/CHANGELOG.rst b/examples/cpp/CHANGELOG.rst index 2c1e759b7..980f322fe 100644 --- a/examples/cpp/CHANGELOG.rst +++ b/examples/cpp/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package wavemap_examples_cpp ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ + 2.1.1 (2024-10-24) ------------------ diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 6bbc58bfe..914e98fe0 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(wavemap_examples_cpp VERSION 2.1.1 LANGUAGES CXX) +project(wavemap_examples_cpp VERSION 2.1.2 LANGUAGES CXX) # Load the wavemap library # First, try to load it from sources diff --git a/examples/python/CHANGELOG.rst b/examples/python/CHANGELOG.rst index a8308ff95..092fa7365 100644 --- a/examples/python/CHANGELOG.rst +++ b/examples/python/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package wavemap_examples_python ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ + 2.1.1 (2024-10-24) ------------------ diff --git a/examples/ros1/CHANGELOG.rst b/examples/ros1/CHANGELOG.rst index ac0f48b72..7cd810a50 100644 --- a/examples/ros1/CHANGELOG.rst +++ b/examples/ros1/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package wavemap_examples_ros1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ + 2.1.1 (2024-10-24) ------------------ * Address warnings from new cpplint version (v2.0) diff --git a/examples/ros1/package.xml b/examples/ros1/package.xml index 03717ebf2..21da126fd 100644 --- a/examples/ros1/package.xml +++ b/examples/ros1/package.xml @@ -1,7 +1,7 @@ wavemap_examples_ros1 - 2.1.1 + 2.1.2 Usages examples for wavemap's ROS1 interface. Victor Reijgwart diff --git a/interfaces/ros1/wavemap/CHANGELOG.rst b/interfaces/ros1/wavemap/CHANGELOG.rst index 0b812bf47..93efbefd8 100644 --- a/interfaces/ros1/wavemap/CHANGELOG.rst +++ b/interfaces/ros1/wavemap/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package wavemap ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ + 2.1.1 (2024-10-24) ------------------ diff --git a/interfaces/ros1/wavemap/package.xml b/interfaces/ros1/wavemap/package.xml index 72df3d4c2..25212d864 100644 --- a/interfaces/ros1/wavemap/package.xml +++ b/interfaces/ros1/wavemap/package.xml @@ -1,7 +1,7 @@ wavemap - 2.1.1 + 2.1.2 Base library for wavemap. Victor Reijgwart diff --git a/interfaces/ros1/wavemap_all/CHANGELOG.rst b/interfaces/ros1/wavemap_all/CHANGELOG.rst index 0b295957b..fb1abe52c 100644 --- a/interfaces/ros1/wavemap_all/CHANGELOG.rst +++ b/interfaces/ros1/wavemap_all/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package wavemap_all ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ + 2.1.1 (2024-10-24) ------------------ diff --git a/interfaces/ros1/wavemap_all/package.xml b/interfaces/ros1/wavemap_all/package.xml index 037f217d7..dbf7e1380 100644 --- a/interfaces/ros1/wavemap_all/package.xml +++ b/interfaces/ros1/wavemap_all/package.xml @@ -1,7 +1,7 @@ wavemap_all - 2.1.1 + 2.1.2 Metapackage that builds all wavemap packages. Victor Reijgwart diff --git a/interfaces/ros1/wavemap_msgs/CHANGELOG.rst b/interfaces/ros1/wavemap_msgs/CHANGELOG.rst index 16625b8ea..a58fdfba4 100644 --- a/interfaces/ros1/wavemap_msgs/CHANGELOG.rst +++ b/interfaces/ros1/wavemap_msgs/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package wavemap_msgs ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ + 2.1.1 (2024-10-24) ------------------ diff --git a/interfaces/ros1/wavemap_msgs/package.xml b/interfaces/ros1/wavemap_msgs/package.xml index 554e3e30b..105e124bb 100644 --- a/interfaces/ros1/wavemap_msgs/package.xml +++ b/interfaces/ros1/wavemap_msgs/package.xml @@ -1,7 +1,7 @@ wavemap_msgs - 2.1.1 + 2.1.2 Message definitions for wavemap's ROS interfaces. Victor Reijgwart diff --git a/interfaces/ros1/wavemap_ros/CHANGELOG.rst b/interfaces/ros1/wavemap_ros/CHANGELOG.rst index 8a99adf3c..f5f4c64bf 100644 --- a/interfaces/ros1/wavemap_ros/CHANGELOG.rst +++ b/interfaces/ros1/wavemap_ros/CHANGELOG.rst @@ -2,6 +2,12 @@ Changelog for package wavemap_ros ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ +* Report CPU, wall time and RAM usage when rosbag_processor completes +* Adjust wavemap config schemas to resolve false positive validation warnings caused by CLion bug IJPL-63581 +* Contributors: Victor Reijgwart + 2.1.1 (2024-10-24) ------------------ * Address warnings from new cpplint version (v2.0) diff --git a/interfaces/ros1/wavemap_ros/app/rosbag_processor.cc b/interfaces/ros1/wavemap_ros/app/rosbag_processor.cc index 295889dfb..c7a809a43 100644 --- a/interfaces/ros1/wavemap_ros/app/rosbag_processor.cc +++ b/interfaces/ros1/wavemap_ros/app/rosbag_processor.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "wavemap_ros/inputs/depth_image_topic_input.h" @@ -75,13 +76,25 @@ int main(int argc, char** argv) { rosbag_processor.enableSimulatedClock(nh); } + // Start measuring resource usage + ResourceMonitor resource_monitor; + resource_monitor.start(); + // Process the rosbag if (!rosbag_processor.processAll()) { return -1; } - wavemap_server.getMap()->prune(); + // Finish processing the map wavemap_server.getPipeline().runOperations(/*force_run_all*/ true); + wavemap_server.getMap()->prune(); + + // Report the resource usage + resource_monitor.stop(); + LOG(INFO) << "Processing complete.\nResource usage:\n" + << resource_monitor.getLastEpisodeResourceUsageStats() + << "\n* Map size: " + << wavemap_server.getMap()->getMemoryUsage() / 1024 << " kB\n"; if (nh_private.param("keep_alive", false)) { ros::spin(); diff --git a/interfaces/ros1/wavemap_ros/config/wavemap_ouster_os0.yaml b/interfaces/ros1/wavemap_ros/config/wavemap_ouster_os0.yaml index c9752d0e9..3f9d71236 100644 --- a/interfaces/ros1/wavemap_ros/config/wavemap_ouster_os0.yaml +++ b/interfaces/ros1/wavemap_ros/config/wavemap_ouster_os0.yaml @@ -50,5 +50,3 @@ inputs: undistort_motion: true topic_queue_length: 10 max_wait_for_pose: { seconds: 1.0 } - # reprojected_pointcloud_topic_name: "/wavemap/reprojected_pointcloud" - # projected_range_image_topic_name: "/wavemap/projected_range_image" diff --git a/interfaces/ros1/wavemap_ros/include/wavemap_ros/map_operations/impl/publish_map_operation_inl.h b/interfaces/ros1/wavemap_ros/include/wavemap_ros/map_operations/impl/publish_map_operation_inl.h index 73010269b..7aa1d1f0d 100644 --- a/interfaces/ros1/wavemap_ros/include/wavemap_ros/map_operations/impl/publish_map_operation_inl.h +++ b/interfaces/ros1/wavemap_ros/include/wavemap_ros/map_operations/impl/publish_map_operation_inl.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/interfaces/ros1/wavemap_ros/package.xml b/interfaces/ros1/wavemap_ros/package.xml index 71ec27eb9..2fb3dc6be 100644 --- a/interfaces/ros1/wavemap_ros/package.xml +++ b/interfaces/ros1/wavemap_ros/package.xml @@ -1,7 +1,7 @@ wavemap_ros - 2.1.1 + 2.1.2 ROS interface for wavemap. Victor Reijgwart diff --git a/interfaces/ros1/wavemap_ros/src/inputs/depth_image_topic_input.cc b/interfaces/ros1/wavemap_ros/src/inputs/depth_image_topic_input.cc index 0b8d8d45d..8b168bf88 100644 --- a/interfaces/ros1/wavemap_ros/src/inputs/depth_image_topic_input.cc +++ b/interfaces/ros1/wavemap_ros/src/inputs/depth_image_topic_input.cc @@ -13,7 +13,7 @@ #include #include #include -#include +#include namespace wavemap { DECLARE_CONFIG_MEMBERS(DepthImageTopicInputConfig, diff --git a/interfaces/ros1/wavemap_ros/src/inputs/pointcloud_topic_input.cc b/interfaces/ros1/wavemap_ros/src/inputs/pointcloud_topic_input.cc index 2cedb59bd..3044f5863 100644 --- a/interfaces/ros1/wavemap_ros/src/inputs/pointcloud_topic_input.cc +++ b/interfaces/ros1/wavemap_ros/src/inputs/pointcloud_topic_input.cc @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include namespace wavemap { diff --git a/interfaces/ros1/wavemap_ros/src/map_operations/publish_map_operation.cc b/interfaces/ros1/wavemap_ros/src/map_operations/publish_map_operation.cc index d2f07fe6c..e44f48a53 100644 --- a/interfaces/ros1/wavemap_ros/src/map_operations/publish_map_operation.cc +++ b/interfaces/ros1/wavemap_ros/src/map_operations/publish_map_operation.cc @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/interfaces/ros1/wavemap_ros/src/map_operations/publish_pointcloud_operation.cc b/interfaces/ros1/wavemap_ros/src/map_operations/publish_pointcloud_operation.cc index 0cb1c3457..4928d232e 100644 --- a/interfaces/ros1/wavemap_ros/src/map_operations/publish_pointcloud_operation.cc +++ b/interfaces/ros1/wavemap_ros/src/map_operations/publish_pointcloud_operation.cc @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include namespace wavemap { diff --git a/interfaces/ros1/wavemap_ros/src/utils/pointcloud_undistorter.cc b/interfaces/ros1/wavemap_ros/src/utils/pointcloud_undistorter.cc index a93c3e2f9..d7e3106a2 100644 --- a/interfaces/ros1/wavemap_ros/src/utils/pointcloud_undistorter.cc +++ b/interfaces/ros1/wavemap_ros/src/utils/pointcloud_undistorter.cc @@ -2,7 +2,7 @@ #include -#include +#include #include #include diff --git a/interfaces/ros1/wavemap_ros/src/utils/rosbag_processor.cc b/interfaces/ros1/wavemap_ros/src/utils/rosbag_processor.cc index fafbcbd0d..158fb0319 100644 --- a/interfaces/ros1/wavemap_ros/src/utils/rosbag_processor.cc +++ b/interfaces/ros1/wavemap_ros/src/utils/rosbag_processor.cc @@ -2,7 +2,7 @@ #include -#include +#include namespace wavemap { RosbagProcessor::~RosbagProcessor() { diff --git a/interfaces/ros1/wavemap_ros_conversions/CHANGELOG.rst b/interfaces/ros1/wavemap_ros_conversions/CHANGELOG.rst index 47e890b14..b8f49bfce 100644 --- a/interfaces/ros1/wavemap_ros_conversions/CHANGELOG.rst +++ b/interfaces/ros1/wavemap_ros_conversions/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package wavemap_ros_conversions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ +* Update include path for profiler_interface.h +* Contributors: Victor Reijgwart + 2.1.1 (2024-10-24) ------------------ * Address warnings from new cpplint version (v2.0) diff --git a/interfaces/ros1/wavemap_ros_conversions/package.xml b/interfaces/ros1/wavemap_ros_conversions/package.xml index b708238fd..abc5ec026 100644 --- a/interfaces/ros1/wavemap_ros_conversions/package.xml +++ b/interfaces/ros1/wavemap_ros_conversions/package.xml @@ -1,7 +1,7 @@ wavemap_ros_conversions - 2.1.1 + 2.1.2 Conversions between wavemap and ROS types. Victor Reijgwart diff --git a/interfaces/ros1/wavemap_ros_conversions/src/map_msg_conversions.cc b/interfaces/ros1/wavemap_ros_conversions/src/map_msg_conversions.cc index d29fda8b5..441aec583 100644 --- a/interfaces/ros1/wavemap_ros_conversions/src/map_msg_conversions.cc +++ b/interfaces/ros1/wavemap_ros_conversions/src/map_msg_conversions.cc @@ -7,7 +7,7 @@ #include #include -#include +#include namespace wavemap::convert { bool mapToRosMsg(const MapBase& map, const std::string& frame_id, diff --git a/interfaces/ros1/wavemap_rviz_plugin/CHANGELOG.rst b/interfaces/ros1/wavemap_rviz_plugin/CHANGELOG.rst index fe1e92ca6..25fe911ce 100644 --- a/interfaces/ros1/wavemap_rviz_plugin/CHANGELOG.rst +++ b/interfaces/ros1/wavemap_rviz_plugin/CHANGELOG.rst @@ -2,6 +2,11 @@ Changelog for package wavemap_rviz_plugin ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ +* Report CPU, wall time and RAM usage when rosbag_processor completes +* Contributors: Victor Reijgwart + 2.1.1 (2024-10-24) ------------------ * Address warnings from new cpplint version (v2.0) diff --git a/interfaces/ros1/wavemap_rviz_plugin/package.xml b/interfaces/ros1/wavemap_rviz_plugin/package.xml index 212539e10..043783900 100644 --- a/interfaces/ros1/wavemap_rviz_plugin/package.xml +++ b/interfaces/ros1/wavemap_rviz_plugin/package.xml @@ -1,7 +1,7 @@ wavemap_rviz_plugin - 2.1.1 + 2.1.2 Plugin to interactively visualize maps published in wavemap's native format. diff --git a/interfaces/ros1/wavemap_rviz_plugin/src/visuals/voxel_visual.cc b/interfaces/ros1/wavemap_rviz_plugin/src/visuals/voxel_visual.cc index b32973a97..1b7fe412c 100644 --- a/interfaces/ros1/wavemap_rviz_plugin/src/visuals/voxel_visual.cc +++ b/interfaces/ros1/wavemap_rviz_plugin/src/visuals/voxel_visual.cc @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace wavemap::rviz_plugin { VoxelVisual::VoxelVisual(Ogre::SceneManager* scene_manager, diff --git a/interfaces/ros1/wavemap_rviz_plugin/src/wavemap_map_display.cc b/interfaces/ros1/wavemap_rviz_plugin/src/wavemap_map_display.cc index 948ce16df..a9452c92e 100644 --- a/interfaces/ros1/wavemap_rviz_plugin/src/wavemap_map_display.cc +++ b/interfaces/ros1/wavemap_rviz_plugin/src/wavemap_map_display.cc @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/library/cpp/CHANGELOG.rst b/library/cpp/CHANGELOG.rst index 2a2d4aa57..9b4fc340a 100644 --- a/library/cpp/CHANGELOG.rst +++ b/library/cpp/CHANGELOG.rst @@ -2,6 +2,13 @@ Changelog for package wavemap ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ +* Adds a ResourceMonitor class for measuring CPU time, wall time, and RAM usage during macro-benchmarking +* Document and add unit tests for the Stopwatch and ResourceMonitor classes +* Extend ThreadPool unit tests +* Contributors: Victor Reijgwart + 2.1.1 (2024-10-24) ------------------ * Address warnings from new cpplint version (v2.0) diff --git a/library/cpp/CMakeLists.txt b/library/cpp/CMakeLists.txt index 4935ffdc1..39c81ec8d 100644 --- a/library/cpp/CMakeLists.txt +++ b/library/cpp/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(wavemap VERSION 2.1.1 LANGUAGES CXX) +project(wavemap VERSION 2.1.2 LANGUAGES CXX) # General options cmake_policy(SET CMP0077 NEW) diff --git a/library/cpp/include/wavemap/core/utils/profiler_interface.h b/library/cpp/include/wavemap/core/utils/profile/profiler_interface.h similarity index 75% rename from library/cpp/include/wavemap/core/utils/profiler_interface.h rename to library/cpp/include/wavemap/core/utils/profile/profiler_interface.h index 9362b4938..000976857 100644 --- a/library/cpp/include/wavemap/core/utils/profiler_interface.h +++ b/library/cpp/include/wavemap/core/utils/profile/profiler_interface.h @@ -1,5 +1,5 @@ -#ifndef WAVEMAP_CORE_UTILS_PROFILER_INTERFACE_H_ -#define WAVEMAP_CORE_UTILS_PROFILER_INTERFACE_H_ +#ifndef WAVEMAP_CORE_UTILS_PROFILE_PROFILER_INTERFACE_H_ +#define WAVEMAP_CORE_UTILS_PROFILE_PROFILER_INTERFACE_H_ #ifdef TRACY_ENABLE @@ -29,4 +29,4 @@ #endif -#endif // WAVEMAP_CORE_UTILS_PROFILER_INTERFACE_H_ +#endif // WAVEMAP_CORE_UTILS_PROFILE_PROFILER_INTERFACE_H_ diff --git a/library/cpp/include/wavemap/core/utils/profile/resource_monitor.h b/library/cpp/include/wavemap/core/utils/profile/resource_monitor.h new file mode 100644 index 000000000..1e979509b --- /dev/null +++ b/library/cpp/include/wavemap/core/utils/profile/resource_monitor.h @@ -0,0 +1,177 @@ +#ifndef WAVEMAP_CORE_UTILS_PROFILE_RESOURCE_MONITOR_H_ +#define WAVEMAP_CORE_UTILS_PROFILE_RESOURCE_MONITOR_H_ + +#include +#include +#include + +#include "wavemap/core/common.h" +#include "wavemap/core/utils/time/time.h" + +namespace wavemap { +/** + * @brief Monitors system resource usage, including CPU time, wall time, + * and RAM usage. + * + * The `ResourceMonitor` class tracks CPU and wall clock time over timed + * episodes, much like wavemap's Stopwatch class. It also provides + * functionality to retrieve the total RAM usage of the current process. + */ +class ResourceMonitor { + public: + /** + * @brief Starts a new CPU and wall time monitoring episode. + * + * Records the CPU and wall clock start times for the current episode. + * If monitoring is already running, calling `start()` has no effect. + */ + void start(); + + /** + * @brief Stops timing the current episode. + * + * Records the end CPU and wall clock times for the current episode, updating + * the last episode duration and total accumulated duration. If no episode is + * in progress, calling `stop()` has no effect. + */ + void stop(); + + /** + * @brief Checks if the stopwatch is currently running. + * + * @return `true` if the stopwatch is running, `false` otherwise. + */ + bool isRunning() const { return running_; } + + /** + * @brief Gets the current RAM usage of the application. + * + * @return The current RAM usage in kilobytes, or `std::nullopt` (an empty + * optional) if retrieving RAM usage is not supported on the given + * platform. + */ + static std::optional getCurrentRamUsageInKB(); + + /** + * @brief Gets the CPU time duration of the last episode. + * + * @return The CPU time duration of the last episode in seconds. + * + * The value represents the CPU time elapsed during the most recently + * completed pair of `start()` and `stop()` calls. If no episode has been + * completed, this returns 0. + */ + double getLastEpisodeCpuTime() const { + return time::to_seconds(last_episode_cpu_duration_); + } + + /** + * @brief Gets the wall clock time duration of the last episode. + * + * @return The wall clock time duration of the last episode in seconds. + * + * The value represents the real-world time elapsed during the most recently + * completed pair of `start()` and `stop()` calls. If no episode has been + * completed, this returns 0. + */ + double getLastEpisodeWallTime() const { + return time::to_seconds(last_episode_wall_duration_); + } + + /** + * @brief Get the last episode's resource usage stats formatted as a string. + * + * @return A string with the CPU time, wall time, and RAM usage statistics. + * + * The returned string provides a human-readable summary of the resource + * usage for the most recently completed episode. CPU and wall times are + * displayed in seconds with two decimal places, while RAM usage is reported + * in kilobytes. If RAM usage information is unavailable, it will be labeled + * as "Unknown". Each statistic is printed on a new line, with a leading `*`. + */ + std::string getLastEpisodeResourceUsageStats() const; + + /** + * @brief Gets the total accumulated CPU time of all episodes. + * + * @return The total CPU time in seconds. + * + * The value represents the sum of the CPU times of all episodes that have + * been timed since the creation of the resource monitor or since it was last + * reset. + */ + double getTotalCpuTime() const { + return time::to_seconds(total_cpu_duration_); + } + + /** + * @brief Gets the total accumulated wall clock time of all episodes. + * + * @return The total wall time in seconds. + * + * The value represents the sum of the wall times of all episodes that have + * been timed since the creation of the resource monitor or since it was last + * reset. + */ + double getTotalWallTime() const { + return time::to_seconds(total_wall_duration_); + } + + /** + * @brief Get the total accumulated resource usage stats formatted as a + * string. + * + * @return A string with the CPU time, wall time, and RAM usage statistics. + * + * The returned string provides a human-readable summary of the total resource + * usage for all episodes. CPU and wall times are displayed in seconds with + * two decimal places, while RAM usage is reported in kilobytes. If RAM usage + * information is unavailable, it will be labeled as "Unknown". Each statistic + * is printed on a new line, with a leading `*`. + */ + std::string getTotalResourceUsageStats() const; + + /** + * @brief Resets the stopwatch to its initial state. + * + * This method resets all member variables by reassigning the object to a + * default-constructed instance. + */ + void reset() { *this = ResourceMonitor{}; } + + private: + /// @brief Indicates whether resource monitoring is currently running. + bool running_ = false; + + /// @brief Stores the CPU time at the start of the current episode. + std::timespec episode_start_cpu_time_{}; + + /// @brief Stores the wall clock time at the start of the current episode. + std::timespec episode_start_wall_time_{}; + + /// @brief Stores the CPU time duration of the last completed episode. + Duration last_episode_cpu_duration_{}; + + /// @brief Stores the wall clock time duration of the last completed episode. + Duration last_episode_wall_duration_{}; + + /// @brief Accumulates the total CPU time duration of all episodes. + Duration total_cpu_duration_{}; + + /// @brief Accumulates the total wall clock time duration of all episodes. + Duration total_wall_duration_{}; + + /** + * @brief Computes the duration between two POSIX timestamps. + * + * @param start The starting POSIX timestamp. + * @param stop The ending POSIX timestamp. + * @return The computed duration as a wavemap::Duration. + */ + static Duration computeDuration(const std::timespec& start, + const std::timespec& stop); +}; + +} // namespace wavemap + +#endif // WAVEMAP_CORE_UTILS_PROFILE_RESOURCE_MONITOR_H_ diff --git a/library/cpp/include/wavemap/core/utils/time/stopwatch.h b/library/cpp/include/wavemap/core/utils/time/stopwatch.h index 2021ceb46..ffbdb0690 100644 --- a/library/cpp/include/wavemap/core/utils/time/stopwatch.h +++ b/library/cpp/include/wavemap/core/utils/time/stopwatch.h @@ -4,23 +4,85 @@ #include "wavemap/core/utils/time/time.h" namespace wavemap { +/** + * @brief A simple utility class for measuring elapsed time across episodes. + * + * The `Stopwatch` class allows tracking the duration of multiple timed + * episodes. It provides functionality to start, stop, and retrieve timing + * information for the last episode as well as the total duration of all + * episodes. + */ class Stopwatch { public: + /** + * @brief Starts the stopwatch for a new timing episode. + * + * Records the start time for the current episode. If the stopwatch is + * already running, calling `start()` has no effect. + */ void start(); + + /** + * @brief Stops the stopwatch for the current timing episode. + * + * Records the end time for the current episode and updates the total + * accumulated duration. If the stopwatch is not running, calling `stop()` + * has no effect. + */ void stop(); + /** + * @brief Checks if the stopwatch is currently running. + * + * @return `true` if the stopwatch is running, `false` otherwise. + */ + bool isRunning() const { return running_; } + + /** + * @brief Gets the duration of the last timing episode. + * + * @return The duration of the last episode in seconds as a `double`. + * + * The value represents the time elapsed during the most recently completed + * pair of `start()` and `stop()` calls. If no episode has been completed, + * this returns 0. + */ double getLastEpisodeDuration() const { return time::to_seconds(last_episode_duration_); } + + /** + * @brief Gets the total accumulated duration of all episodes. + * + * @return The total duration in seconds as a `double`. + * + * The value represents the sum of the durations of all episodes that have + * been completed since the creation of the stopwatch or since it was last + * reset. + */ double getTotalDuration() const { return time::to_seconds(total_duration_); } + /** + * @brief Resets the stopwatch to its initial state. + * + * This method resets all member variables by reassigning the object to a + * default-constructed instance. + */ + void reset() { *this = Stopwatch{}; } + private: - bool running = false; + /// @brief Indicates whether the stopwatch is currently running. + bool running_ = false; + /// @brief Stores the start time of the current episode. Timestamp episode_start_time_{}; + + /// @brief Stores the duration of the last completed episode. Duration last_episode_duration_{}; + + /// @brief Accumulates the total duration of all episodes. Duration total_duration_{}; }; } // namespace wavemap diff --git a/library/cpp/src/core/CMakeLists.txt b/library/cpp/src/core/CMakeLists.txt index 9835c4d8e..a48abab05 100644 --- a/library/cpp/src/core/CMakeLists.txt +++ b/library/cpp/src/core/CMakeLists.txt @@ -42,6 +42,7 @@ target_sources(wavemap_core PRIVATE map/wavelet_octree.cc map/map_base.cc map/map_factory.cc + utils/profile/resource_monitor.cc utils/query/classified_map.cc utils/query/query_accelerator.cc utils/query/point_sampler.cc diff --git a/library/cpp/src/core/integrator/projective/coarse_to_fine/hashed_chunked_wavelet_integrator.cc b/library/cpp/src/core/integrator/projective/coarse_to_fine/hashed_chunked_wavelet_integrator.cc index 6d42c34e4..3352217c9 100644 --- a/library/cpp/src/core/integrator/projective/coarse_to_fine/hashed_chunked_wavelet_integrator.cc +++ b/library/cpp/src/core/integrator/projective/coarse_to_fine/hashed_chunked_wavelet_integrator.cc @@ -5,7 +5,7 @@ #include #include -#include +#include namespace wavemap { void HashedChunkedWaveletIntegrator::updateMap() { diff --git a/library/cpp/src/core/integrator/projective/coarse_to_fine/hashed_wavelet_integrator.cc b/library/cpp/src/core/integrator/projective/coarse_to_fine/hashed_wavelet_integrator.cc index 515ccd3cd..9168b35cd 100644 --- a/library/cpp/src/core/integrator/projective/coarse_to_fine/hashed_wavelet_integrator.cc +++ b/library/cpp/src/core/integrator/projective/coarse_to_fine/hashed_wavelet_integrator.cc @@ -5,7 +5,7 @@ #include #include -#include +#include namespace wavemap { void HashedWaveletIntegrator::updateMap() { diff --git a/library/cpp/src/core/integrator/projective/projective_integrator.cc b/library/cpp/src/core/integrator/projective/projective_integrator.cc index b61b169d5..cadd3cdc8 100644 --- a/library/cpp/src/core/integrator/projective/projective_integrator.cc +++ b/library/cpp/src/core/integrator/projective/projective_integrator.cc @@ -1,7 +1,7 @@ #include "wavemap/core/integrator/projective/projective_integrator.h" #include -#include +#include namespace wavemap { DECLARE_CONFIG_MEMBERS(ProjectiveIntegratorConfig, diff --git a/library/cpp/src/core/map/hashed_chunked_wavelet_octree.cc b/library/cpp/src/core/map/hashed_chunked_wavelet_octree.cc index 6f33b017f..702a0eba6 100644 --- a/library/cpp/src/core/map/hashed_chunked_wavelet_octree.cc +++ b/library/cpp/src/core/map/hashed_chunked_wavelet_octree.cc @@ -2,7 +2,7 @@ #include -#include +#include namespace wavemap { DECLARE_CONFIG_MEMBERS(HashedChunkedWaveletOctreeConfig, diff --git a/library/cpp/src/core/map/hashed_chunked_wavelet_octree_block.cc b/library/cpp/src/core/map/hashed_chunked_wavelet_octree_block.cc index 888f0c9b6..d9aea9bb8 100644 --- a/library/cpp/src/core/map/hashed_chunked_wavelet_octree_block.cc +++ b/library/cpp/src/core/map/hashed_chunked_wavelet_octree_block.cc @@ -3,7 +3,7 @@ #include #include -#include +#include namespace wavemap { void HashedChunkedWaveletOctreeBlock::threshold() { diff --git a/library/cpp/src/core/map/hashed_wavelet_octree.cc b/library/cpp/src/core/map/hashed_wavelet_octree.cc index 7d9a9abf2..91c468527 100644 --- a/library/cpp/src/core/map/hashed_wavelet_octree.cc +++ b/library/cpp/src/core/map/hashed_wavelet_octree.cc @@ -2,7 +2,7 @@ #include -#include +#include namespace wavemap { DECLARE_CONFIG_MEMBERS(HashedWaveletOctreeConfig, diff --git a/library/cpp/src/core/map/hashed_wavelet_octree_block.cc b/library/cpp/src/core/map/hashed_wavelet_octree_block.cc index e5e982a5d..7ab3ec524 100644 --- a/library/cpp/src/core/map/hashed_wavelet_octree_block.cc +++ b/library/cpp/src/core/map/hashed_wavelet_octree_block.cc @@ -3,7 +3,7 @@ #include #include -#include +#include namespace wavemap { void HashedWaveletOctreeBlock::threshold() { diff --git a/library/cpp/src/core/utils/profile/resource_monitor.cc b/library/cpp/src/core/utils/profile/resource_monitor.cc new file mode 100644 index 000000000..86b0b4ce8 --- /dev/null +++ b/library/cpp/src/core/utils/profile/resource_monitor.cc @@ -0,0 +1,123 @@ +#include "wavemap/core/utils/profile/resource_monitor.h" + +#include +#include +#include +#include +#include + +// Borrowed from BOOST_HAS_CLOCK_GETTIME +// NOTE: This is predicated on _POSIX_TIMERS (also on _XOPEN_REALTIME +// but at least one platform - linux - defines that flag without +// defining clock_gettime): +#if (defined(_POSIX_TIMERS) && (_POSIX_TIMERS + 0 >= 0)) +#define HAS_CLOCK_GETTIME +#endif + +namespace wavemap { +void ResourceMonitor::start() { + if (running_) { + LOG(WARNING) << "Tried to start timer that was already running."; + return; + } + +#ifdef HAS_CLOCK_GETTIME + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &episode_start_cpu_time_); + clock_gettime(CLOCK_MONOTONIC, &episode_start_wall_time_); +#else + LOG(WARNING) << "Measuring CPU time has not yet been implemented for the " + "current platform."; +#endif + running_ = true; +} + +void ResourceMonitor::stop() { + if (!running_) { + LOG(WARNING) << "Tried to stop timer that was not running."; + return; + } + + std::timespec episode_stop_cpu_time{}; + std::timespec episode_stop_wall_time{}; +#ifdef HAS_CLOCK_GETTIME + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &episode_stop_cpu_time); + clock_gettime(CLOCK_MONOTONIC, &episode_stop_wall_time); +#else + LOG(WARNING) << "Measuring CPU time has not yet been implemented for the " + "current platform."; +#endif + running_ = false; + + last_episode_cpu_duration_ = + computeDuration(episode_start_cpu_time_, episode_stop_cpu_time); + last_episode_wall_duration_ = + computeDuration(episode_start_wall_time_, episode_stop_wall_time); + total_cpu_duration_ += last_episode_cpu_duration_; + total_wall_duration_ += last_episode_wall_duration_; +} + +std::optional ResourceMonitor::getCurrentRamUsageInKB() { + std::ifstream file("/proc/self/status"); + std::string line; + while (std::getline(file, line)) { + if (line.rfind("VmRSS", 0) == 0) { + break; + } + } + if (file.eof()) { + LOG(ERROR) << "Failed to read RAM usage. Could not find VmRSS entry in " + "\"/proc/self/status\"."; + return std::nullopt; + } + + std::string quantity; + size_t ram_usage; + std::string unit; + if (std::istringstream iss(line); !(iss >> quantity >> ram_usage >> unit)) { + LOG(ERROR) << "Failed to read RAM usage. Could not parse VmRSS line " + "in \"/proc/self/status\"."; + return std::nullopt; + } + + if (unit != "kB") { + LOG(ERROR) << "Failed to read RAM usage. Expected VmRSS entry in " + "\"/proc/self/status\" to be specified in kB, got " + << unit << "."; + return std::nullopt; + } + + return ram_usage; +} + +std::string ResourceMonitor::getLastEpisodeResourceUsageStats() const { + std::ostringstream oss; + oss << std::fixed << std::setprecision(2); // Print with two decimals + oss << "* CPU time: " << getLastEpisodeCpuTime() << " s\n" + << "* Wall time: " << getLastEpisodeWallTime() << " s\n"; + if (const auto ram_usage = getCurrentRamUsageInKB(); ram_usage) { + oss << "* RAM total: " << *ram_usage << " kB"; + } else { + oss << "* RAM total: Unknown"; + } + return oss.str(); +} + +std::string ResourceMonitor::getTotalResourceUsageStats() const { + std::ostringstream oss; + oss << std::fixed << std::setprecision(2); // Print with two decimals + oss << "* CPU time: " << getTotalCpuTime() << " s\n" + << "* Wall time: " << getTotalWallTime() << " s\n"; + if (const auto ram_usage = getCurrentRamUsageInKB(); ram_usage) { + oss << "* RAM total: " << *ram_usage << " kB"; + } else { + oss << "* RAM total: Unknown"; + } + return oss.str(); +} + +Duration ResourceMonitor::computeDuration(const std::timespec& start, + const std::timespec& stop) { + return std::chrono::seconds(stop.tv_sec - start.tv_sec) + + std::chrono::nanoseconds(stop.tv_nsec - start.tv_nsec); +} +} // namespace wavemap diff --git a/library/cpp/src/core/utils/query/classified_map.cc b/library/cpp/src/core/utils/query/classified_map.cc index 7eadb489b..7ebd9e4b3 100644 --- a/library/cpp/src/core/utils/query/classified_map.cc +++ b/library/cpp/src/core/utils/query/classified_map.cc @@ -5,7 +5,7 @@ #include #include -#include +#include namespace wavemap { ClassifiedMap::ClassifiedMap(FloatingPoint min_cell_width, diff --git a/library/cpp/src/core/utils/sdf/full_euclidean_sdf_generator.cc b/library/cpp/src/core/utils/sdf/full_euclidean_sdf_generator.cc index 4cb414aaf..a91ae4406 100644 --- a/library/cpp/src/core/utils/sdf/full_euclidean_sdf_generator.cc +++ b/library/cpp/src/core/utils/sdf/full_euclidean_sdf_generator.cc @@ -1,6 +1,6 @@ #include "wavemap/core/utils/sdf/full_euclidean_sdf_generator.h" -#include +#include #include "wavemap/core/utils/iterate/grid_iterator.h" #include "wavemap/core/utils/query/query_accelerator.h" diff --git a/library/cpp/src/core/utils/sdf/quasi_euclidean_sdf_generator.cc b/library/cpp/src/core/utils/sdf/quasi_euclidean_sdf_generator.cc index 675203cbe..c97ff72a1 100644 --- a/library/cpp/src/core/utils/sdf/quasi_euclidean_sdf_generator.cc +++ b/library/cpp/src/core/utils/sdf/quasi_euclidean_sdf_generator.cc @@ -2,7 +2,7 @@ #include -#include +#include #include "wavemap/core/utils/iterate/grid_iterator.h" #include "wavemap/core/utils/query/query_accelerator.h" diff --git a/library/cpp/src/core/utils/thread_pool.cc b/library/cpp/src/core/utils/thread_pool.cc index 2d48bdf05..25a651ca9 100644 --- a/library/cpp/src/core/utils/thread_pool.cc +++ b/library/cpp/src/core/utils/thread_pool.cc @@ -3,7 +3,7 @@ #include #include -#include +#include namespace wavemap { ThreadPool::ThreadPool(size_t thread_count) diff --git a/library/cpp/src/core/utils/time/stopwatch.cc b/library/cpp/src/core/utils/time/stopwatch.cc index c023dc506..24957d71d 100644 --- a/library/cpp/src/core/utils/time/stopwatch.cc +++ b/library/cpp/src/core/utils/time/stopwatch.cc @@ -4,21 +4,21 @@ namespace wavemap { void Stopwatch::start() { - if (running) { + if (running_) { LOG(WARNING) << "Tried to start timer that was already running."; return; } episode_start_time_ = Time::now(); - running = true; + running_ = true; } void Stopwatch::stop() { - if (!running) { + if (!running_) { LOG(WARNING) << "Tried to stop timer that was not running."; return; } const Timestamp stop_wall_time = Time::now(); - running = false; + running_ = false; last_episode_duration_ = stop_wall_time - episode_start_time_; total_duration_ += last_episode_duration_; diff --git a/library/cpp/test/src/core/CMakeLists.txt b/library/cpp/test/src/core/CMakeLists.txt index e0a8e94a0..cb246e0ec 100644 --- a/library/cpp/test/src/core/CMakeLists.txt +++ b/library/cpp/test/src/core/CMakeLists.txt @@ -34,12 +34,14 @@ target_sources(test_wavemap_core PRIVATE utils/neighbors/test_grid_adjacency.cc utils/neighbors/test_grid_neighborhood.cc utils/neighbors/test_ndtree_adjacency.cc + utils/profile/test_resource_monitor.cc utils/query/test_classified_map.cc utils/query/test_map_interpolator.cpp utils/query/test_occupancy_classifier.cc utils/query/test_probability_conversions.cc utils/query/test_query_accelerator.cc utils/sdf/test_sdf_generators.cc + utils/time/test_stopwatch.cc utils/test_thread_pool.cc) set_wavemap_target_properties(test_wavemap_core) diff --git a/library/cpp/test/src/core/utils/profile/test_resource_monitor.cc b/library/cpp/test/src/core/utils/profile/test_resource_monitor.cc new file mode 100644 index 000000000..7501b532d --- /dev/null +++ b/library/cpp/test/src/core/utils/profile/test_resource_monitor.cc @@ -0,0 +1,99 @@ +#include + +#include + +#include "wavemap/core/utils/profile/resource_monitor.h" + +namespace wavemap { +class ResourceMonitorTest : public ::testing::Test { + protected: + ResourceMonitor resource_monitor; +}; + +TEST_F(ResourceMonitorTest, InitialState) { + EXPECT_FALSE(resource_monitor.isRunning()); + EXPECT_EQ(resource_monitor.getLastEpisodeCpuTime(), 0.0); + EXPECT_EQ(resource_monitor.getLastEpisodeWallTime(), 0.0); + EXPECT_EQ(resource_monitor.getTotalCpuTime(), 0.0); + EXPECT_EQ(resource_monitor.getTotalWallTime(), 0.0); +} + +TEST_F(ResourceMonitorTest, Start) { + resource_monitor.start(); + EXPECT_TRUE(resource_monitor.isRunning()); +} + +TEST_F(ResourceMonitorTest, Stop) { + resource_monitor.start(); + resource_monitor.stop(); + EXPECT_FALSE(resource_monitor.isRunning()); +} + +TEST_F(ResourceMonitorTest, Reset) { + resource_monitor.start(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + resource_monitor.stop(); + + resource_monitor.reset(); + EXPECT_FALSE(resource_monitor.isRunning()); + EXPECT_EQ(resource_monitor.getLastEpisodeCpuTime(), 0.0); + EXPECT_EQ(resource_monitor.getLastEpisodeWallTime(), 0.0); + EXPECT_EQ(resource_monitor.getTotalCpuTime(), 0.0); + EXPECT_EQ(resource_monitor.getTotalWallTime(), 0.0); +} + +TEST_F(ResourceMonitorTest, DurationTracking) { + resource_monitor.start(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + resource_monitor.stop(); + + const double first_wall_time = resource_monitor.getLastEpisodeWallTime(); + EXPECT_GT(first_wall_time, 0.09); // Allow for small timing inaccuracies + EXPECT_LT(first_wall_time, 0.11); // Tolerance of ±10ms + + const double first_cpu_time = resource_monitor.getLastEpisodeCpuTime(); + EXPECT_GT(first_cpu_time, 0.0); // CPU time should be non-zero + + EXPECT_EQ(resource_monitor.getTotalWallTime(), first_wall_time); + EXPECT_EQ(resource_monitor.getTotalCpuTime(), first_cpu_time); + + resource_monitor.start(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + resource_monitor.stop(); + + const double second_wall_time = resource_monitor.getLastEpisodeWallTime(); + EXPECT_GT(second_wall_time, 0.04); // Allow for small timing inaccuracies + EXPECT_LT(second_wall_time, 0.06); // Tolerance of ±10ms + + const double second_cpu_time = resource_monitor.getLastEpisodeCpuTime(); + EXPECT_DOUBLE_EQ(resource_monitor.getTotalWallTime(), + first_wall_time + second_wall_time); + EXPECT_DOUBLE_EQ(resource_monitor.getTotalCpuTime(), + first_cpu_time + second_cpu_time); +} + +TEST_F(ResourceMonitorTest, StopWithoutStart) { + resource_monitor.stop(); + EXPECT_FALSE(resource_monitor.isRunning()); + EXPECT_EQ(resource_monitor.getLastEpisodeCpuTime(), 0.0); + EXPECT_EQ(resource_monitor.getLastEpisodeWallTime(), 0.0); +} + +TEST_F(ResourceMonitorTest, MultipleStarts) { + resource_monitor.start(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + resource_monitor.start(); // Should have no effect + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + resource_monitor.stop(); + + const double wall_time = resource_monitor.getLastEpisodeWallTime(); + EXPECT_GT(wall_time, 0.14); // Combined duration + EXPECT_LT(wall_time, 0.16); // Tolerance of ±10ms +} + +TEST_F(ResourceMonitorTest, RamUsage) { + const auto ram_usage = ResourceMonitor::getCurrentRamUsageInKB(); + ASSERT_TRUE(ram_usage.has_value()); // Check if the optional contains a value + EXPECT_GT(ram_usage.value(), 0); // RAM usage should be a positive value +} +} // namespace wavemap diff --git a/library/cpp/test/src/core/utils/test_thread_pool.cc b/library/cpp/test/src/core/utils/test_thread_pool.cc index 6b1ab5dda..5e60c67ac 100644 --- a/library/cpp/test/src/core/utils/test_thread_pool.cc +++ b/library/cpp/test/src/core/utils/test_thread_pool.cc @@ -1,20 +1,71 @@ #include #include +#include +#include #include #include "wavemap/core/utils/thread_pool.h" +#include "wavemap/core/utils/time/stopwatch.h" +namespace wavemap { TEST(ThreadPoolTest, WaitAll) { - auto dummy_fn = []() { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - }; + constexpr Duration kSleepTime = std::chrono::milliseconds{10}; + auto dummy_fn = [kSleepTime]() { std::this_thread::sleep_for(kSleepTime); }; - wavemap::ThreadPool pool(2); - pool.add_task(dummy_fn); - pool.add_task(dummy_fn); - pool.add_task(dummy_fn); - pool.add_task(dummy_fn); + // Create the thread pool + constexpr int kNumThreads = 2; + ThreadPool pool(kNumThreads); + // Start measuring time + Stopwatch stopwatch; + stopwatch.start(); + + // Add the tasks to the pool + constexpr int kNumTasks = 4; + std::vector> futures; + futures.reserve(kNumTasks); + for (int task_idx = 0; task_idx < kNumTasks; ++task_idx) { + auto future = pool.add_task(dummy_fn); + futures.emplace_back(std::move(future)); + } pool.wait_all(); + stopwatch.stop(); + + // Check that all futures are available after calling wait_all + for (int task_idx = 0; task_idx < kNumTasks; ++task_idx) { + auto& future = futures[task_idx]; + EXPECT_TRUE(future.valid()); + } + + // Check that executing the tasks took as long as expected + EXPECT_GE(stopwatch.getLastEpisodeDuration(), + time::to_seconds(kSleepTime * kNumTasks / kNumThreads)); +} + +TEST(ThreadPoolTest, FutureResults) { + constexpr int kNumThreads = 2; + ThreadPool pool(kNumThreads); + + // Add the tasks to the pool + constexpr int kNumTasks = 4; + std::vector> futures; + futures.reserve(kNumTasks); + for (int task_idx = 0; task_idx < kNumTasks; ++task_idx) { + const auto sleep_time = std::chrono::milliseconds(kNumTasks - task_idx); + auto future = pool.add_task([task_idx, sleep_time]() { + std::this_thread::sleep_for(sleep_time); + return task_idx; + }); + futures.emplace_back(std::move(future)); + } + + // Wait for the futures one by one and check their results + for (int task_idx = 0; task_idx < kNumTasks; ++task_idx) { + auto& future = futures[task_idx]; + future.wait(); + EXPECT_TRUE(future.valid()); + EXPECT_EQ(future.get(), task_idx); + } } +} // namespace wavemap diff --git a/library/cpp/test/src/core/utils/time/test_stopwatch.cc b/library/cpp/test/src/core/utils/time/test_stopwatch.cc new file mode 100644 index 000000000..8b968129d --- /dev/null +++ b/library/cpp/test/src/core/utils/time/test_stopwatch.cc @@ -0,0 +1,85 @@ +#include + +#include + +#include "wavemap/core/utils/time/stopwatch.h" + +namespace wavemap { +class StopwatchTest : public ::testing::Test { + protected: + Stopwatch stopwatch; +}; + +TEST_F(StopwatchTest, InitialState) { + EXPECT_FALSE(stopwatch.isRunning()); + EXPECT_EQ(stopwatch.getLastEpisodeDuration(), 0.0); + EXPECT_EQ(stopwatch.getTotalDuration(), 0.0); +} + +TEST_F(StopwatchTest, Start) { + stopwatch.start(); + EXPECT_TRUE(stopwatch.isRunning()); +} + +TEST_F(StopwatchTest, Stop) { + stopwatch.start(); + stopwatch.stop(); + EXPECT_FALSE(stopwatch.isRunning()); +} + +TEST_F(StopwatchTest, Reset) { + stopwatch.start(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + stopwatch.stop(); + + stopwatch.reset(); + EXPECT_FALSE(stopwatch.isRunning()); + EXPECT_EQ(stopwatch.getLastEpisodeDuration(), 0.0); + EXPECT_EQ(stopwatch.getTotalDuration(), 0.0); +} + +TEST_F(StopwatchTest, DurationTracking) { + stopwatch.start(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + stopwatch.stop(); + + const double first_episode_duration = stopwatch.getLastEpisodeDuration(); + EXPECT_GT(first_episode_duration, + 0.09); // Allow for small timing inaccuracies + EXPECT_LT(first_episode_duration, 0.11); // Tolerance of ±10ms + + const double total_duration = stopwatch.getTotalDuration(); + EXPECT_DOUBLE_EQ(first_episode_duration, total_duration); + + stopwatch.start(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + stopwatch.stop(); + + const double second_episode_duration = stopwatch.getLastEpisodeDuration(); + EXPECT_GT(second_episode_duration, + 0.04); // Allow for small timing inaccuracies + EXPECT_LT(second_episode_duration, 0.06); // Tolerance of ±10ms + + EXPECT_DOUBLE_EQ(stopwatch.getTotalDuration(), + first_episode_duration + second_episode_duration); +} + +TEST_F(StopwatchTest, StopWithoutStart) { + stopwatch.stop(); + EXPECT_FALSE(stopwatch.isRunning()); + EXPECT_EQ(stopwatch.getLastEpisodeDuration(), 0.0); + EXPECT_EQ(stopwatch.getTotalDuration(), 0.0); +} + +TEST_F(StopwatchTest, MultipleStarts) { + stopwatch.start(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + stopwatch.start(); // Should have no effect + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + stopwatch.stop(); + + const double episode_duration = stopwatch.getLastEpisodeDuration(); + EXPECT_GT(episode_duration, 0.14); // Combined duration + EXPECT_LT(episode_duration, 0.16); // Tolerance of ±10ms +} +} // namespace wavemap diff --git a/library/python/CHANGELOG.rst b/library/python/CHANGELOG.rst index f53ecc405..58898d3ec 100644 --- a/library/python/CHANGELOG.rst +++ b/library/python/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package pywavemap ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ + 2.1.1 (2024-10-24) ------------------ * Address warnings from new cpplint version (v2.0) diff --git a/library/python/CMakeLists.txt b/library/python/CMakeLists.txt index 0133b8f7c..fae701f9c 100644 --- a/library/python/CMakeLists.txt +++ b/library/python/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.18) -project(pywavemap VERSION 2.1.1 LANGUAGES CXX) +project(pywavemap VERSION 2.1.2 LANGUAGES CXX) # Warn if the user invokes CMake directly if (NOT SKBUILD AND NOT $ENV{CLION_IDE}) diff --git a/library/python/pyproject.toml b/library/python/pyproject.toml index b8c9e7899..c4fe49030 100644 --- a/library/python/pyproject.toml +++ b/library/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build" [project] name = "pywavemap" -version = "2.1.1" +version = "2.1.2" description = "A fast, efficient and accurate multi-resolution, multi-sensor 3D occupancy mapping framework." readme = "../../README.md" requires-python = ">=3.8" diff --git a/tooling/packages/catkin_setup/CHANGELOG.rst b/tooling/packages/catkin_setup/CHANGELOG.rst index e0c79c994..a8ff8a2e1 100644 --- a/tooling/packages/catkin_setup/CHANGELOG.rst +++ b/tooling/packages/catkin_setup/CHANGELOG.rst @@ -2,6 +2,9 @@ Changelog for package catkin_setup ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2.1.2 (2024-11-20) +------------------ + 2.1.1 (2024-10-24) ------------------ diff --git a/tooling/packages/catkin_setup/package.xml b/tooling/packages/catkin_setup/package.xml index d02b5bd8e..8e75b5deb 100644 --- a/tooling/packages/catkin_setup/package.xml +++ b/tooling/packages/catkin_setup/package.xml @@ -1,7 +1,7 @@ catkin_setup - 2.1.1 + 2.1.2 Dummy package to make it easy to setup the workspace and generate the setup.[sh|bash|zsh] scripts in CI. Victor Reijgwart diff --git a/tooling/schemas/wavemap/inputs/input_base.json b/tooling/schemas/wavemap/inputs/input_base.json index 9682e779e..5e61a1392 100644 --- a/tooling/schemas/wavemap/inputs/input_base.json +++ b/tooling/schemas/wavemap/inputs/input_base.json @@ -15,7 +15,7 @@ ] } }, - "oneOf": [ + "anyOf": [ { "$ref": "pointcloud_input.json" }, diff --git a/tooling/schemas/wavemap/map/map_base.json b/tooling/schemas/wavemap/map/map_base.json index 754438bdb..f97c463a7 100644 --- a/tooling/schemas/wavemap/map/map_base.json +++ b/tooling/schemas/wavemap/map/map_base.json @@ -18,7 +18,7 @@ ] } }, - "oneOf": [ + "anyOf": [ { "$ref": "hashed_blocks.json" }, diff --git a/tooling/schemas/wavemap/map_operations/map_operation_base.json b/tooling/schemas/wavemap/map_operations/map_operation_base.json index 3d573e55a..23a053d81 100644 --- a/tooling/schemas/wavemap/map_operations/map_operation_base.json +++ b/tooling/schemas/wavemap/map_operations/map_operation_base.json @@ -18,7 +18,7 @@ ] } }, - "oneOf": [ + "anyOf": [ { "$ref": "threshold_map_operation.json" }, diff --git a/tooling/schemas/wavemap/measurement_integrators/integration_method.json b/tooling/schemas/wavemap/measurement_integrators/integration_method.json index 8b522f020..6859ea8a9 100644 --- a/tooling/schemas/wavemap/measurement_integrators/integration_method.json +++ b/tooling/schemas/wavemap/measurement_integrators/integration_method.json @@ -71,7 +71,7 @@ "required": [ "type" ], - "oneOf": [ + "anyOf": [ { "$ref": "#/$defs/ray_tracing_integrator" }, diff --git a/tooling/schemas/wavemap/measurement_integrators/measurement_model.json b/tooling/schemas/wavemap/measurement_integrators/measurement_model.json index 15078c295..3965dea11 100644 --- a/tooling/schemas/wavemap/measurement_integrators/measurement_model.json +++ b/tooling/schemas/wavemap/measurement_integrators/measurement_model.json @@ -95,7 +95,7 @@ ] } }, - "oneOf": [ + "anyOf": [ { "$ref": "#/$defs/constant_ray" }, diff --git a/tooling/schemas/wavemap/measurement_integrators/projection_model.json b/tooling/schemas/wavemap/measurement_integrators/projection_model.json index 0f727a631..b842f5d61 100644 --- a/tooling/schemas/wavemap/measurement_integrators/projection_model.json +++ b/tooling/schemas/wavemap/measurement_integrators/projection_model.json @@ -111,7 +111,7 @@ ] } }, - "oneOf": [ + "anyOf": [ { "$ref": "#/$defs/spherical_projector" },