rclcpp/rclcpp/test/topic_statistics/test_topic_stats_utils.hpp
Devin Bonnie bb91b6c2ef
Integrate topic statistics (#1072)
* Add SubscriberTopicStatistics class

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Add SubscriberTopicStatistics Test

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Modify constructor to allow a node to create necessary components

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Fix docstring style

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Remove SetPublisherTimer method

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Change naming style to match rclcpp

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address style issues

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Use rclcpp:Time

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Remove unnecessary check for null publisher timer
Move anonymous namespace function to private class method

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Update message dependency

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Initial integration of Subscriber Topic Statistics

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Fix nanoseconds used for Topic Stats

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Add simple publishing test
Minor fixes

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Add test utils header

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Integrate with Topic Statistics options
Fixes after rebasing with master

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Update after rebasing

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address minor review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Move Topic Statistics instantiation to create_subscription

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Fix rebase issue
Fix topic statistics enable flag usage
Address minor formatting

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Move new timer creation method to relevant header

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Add timers interface to topic interface

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Use new create timer method

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>

* Address review comments

Signed-off-by: Devin Bonnie <dbbonnie@amazon.com>
2020-04-22 16:09:41 -07:00

151 lines
4.2 KiB
C++

// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <atomic>
#include <functional>
#include <future>
#include <memory>
#include <mutex>
#include <string>
#include "statistics_msgs/msg/metrics_message.hpp"
#ifndef TOPIC_STATISTICS__TEST_TOPIC_STATS_UTILS_HPP_
#define TOPIC_STATISTICS__TEST_TOPIC_STATS_UTILS_HPP_
namespace rclcpp
{
namespace topic_statistics
{
using statistics_msgs::msg::MetricsMessage;
/**
* Provide an interface to wait for a promise to be satisfied via its future.
*/
class PromiseSetter
{
public:
/**
* Reassign the promise member and return it's future. Acquires a mutex in order
* to mutate member variables.
*
* \return the promise member's future, called upon PeriodicMeasurement
*/
std::shared_future<bool> GetFuture()
{
std::unique_lock<std::mutex> ulock{mutex_};
use_future_ = true;
promise_ = std::promise<bool>();
return promise_.get_future();
}
protected:
/**
* Set the promise to true, which signals the corresponding future. Acquires a mutex and sets
* the promise to true iff GetFuture was invoked before this.
*/
void SetPromise()
{
std::unique_lock<std::mutex> ulock{mutex_};
if (use_future_) {
// only set if GetFuture was called
promise_.set_value(true);
use_future_ = false; // the promise needs to be reassigned to set again
}
}
private:
mutable std::mutex mutex_;
std::promise<bool> promise_;
bool use_future_{false};
};
/**
* Node which listens for published MetricsMessages. This uses the PromiseSetter API
* in order to signal, via a future, that rclcpp should stop spinning upon
* message handling.
*/
class MetricsMessageSubscriber : public rclcpp::Node, public PromiseSetter
{
public:
/**
* Constructs a MetricsMessageSubscriber.
* \param name the node name
* \param name the topic name
* \param number of messages to receive to trigger the PromiseSetter future
*/
MetricsMessageSubscriber(
const std::string & name,
const std::string & topic_name,
const int number_of_messages_to_receive = 1)
: rclcpp::Node(name),
number_of_messages_to_receive_(number_of_messages_to_receive)
{
auto callback = [this](MetricsMessage::UniquePtr msg) {
this->MetricsMessageCallback(*msg);
};
subscription_ = create_subscription<MetricsMessage,
std::function<void(MetricsMessage::UniquePtr)>>(
topic_name,
0 /*history_depth*/,
callback);
}
/**
* Acquires a mutex in order to get the last message received member.
* \return the last message received
*/
MetricsMessage GetLastReceivedMessage() const
{
std::unique_lock<std::mutex> ulock{mutex_};
return last_received_message_;
}
/**
* Return the number of messages received by this subscriber.
* \return the number of messages received by the subscriber callback
*/
int GetNumberOfMessagesReceived() const
{
return num_messages_received_;
}
private:
/**
* Subscriber callback. Acquires a mutex to set the last message received and
* sets the promise to true.
* \param msg
*/
void MetricsMessageCallback(const MetricsMessage & msg)
{
std::unique_lock<std::mutex> ulock{mutex_};
++num_messages_received_;
last_received_message_ = msg;
if (num_messages_received_ >= number_of_messages_to_receive_) {
PromiseSetter::SetPromise();
}
}
MetricsMessage last_received_message_;
rclcpp::Subscription<MetricsMessage>::SharedPtr subscription_;
mutable std::mutex mutex_;
std::atomic<int> num_messages_received_{0};
const int number_of_messages_to_receive_;
};
} // namespace topic_statistics
} // namespace rclcpp
#endif // TOPIC_STATISTICS__TEST_TOPIC_STATS_UTILS_HPP_