Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make rclcpp::Duration support scale operation #437

Closed
wants to merge 8 commits into from

Conversation

jwang11
Copy link
Contributor

@jwang11 jwang11 commented Feb 13, 2018

Duration scale is a convinient operation which had supported in ROS.
This commit make ROS2 support it.

Signed-off-by: jwang jing.j.wang@intel.com

Duration
Duration::operator*(double scale) const
{
return Duration(rcl_duration_.nanoseconds * scale);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add underflow and overflow checking here. We are checking + and - operations we should check * too.

@@ -54,6 +54,10 @@ TEST(TestDuration, operators) {
EXPECT_EQ(sub.nanoseconds(), (rcl_duration_value_t)(young.nanoseconds() - old.nanoseconds()));
EXPECT_EQ(sub, young - old);

rclcpp::Duration scale = old * 3;
EXPECT_EQ(scale.nanoseconds(), (rcl_duration_value_t)(old.nanoseconds() * 3));
EXPECT_EQ(scale, old * 3);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line doesn't seem to test anything. scale is defined just as old * 3 two lines above. So this will always be true if the operator is deterministic.

Copy link
Contributor Author

@jwang11 jwang11 Feb 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it, the reason I add this check is that the tests for operation +/- both include it, just keep consistent

  rclcpp::Duration add = old + young;
  EXPECT_EQ(add.nanoseconds(), (rcl_duration_value_t)(old.nanoseconds() + young.nanoseconds()));
  EXPECT_EQ(add, old + young);

  rclcpp::Duration sub = young - old;
  EXPECT_EQ(sub.nanoseconds(), (rcl_duration_value_t)(young.nanoseconds() - old.nanoseconds()));
  EXPECT_EQ(sub, young - old);

@mikaelarguedas mikaelarguedas added the in review Waiting for review (Kanban column) label Feb 14, 2018
@mikaelarguedas
Copy link
Member

Thanks @jwang11 for the contribution.
@tfoote of @dirk-thomas to run CI and merge if green

tfoote
tfoote previously requested changes Feb 15, 2018
Copy link
Contributor

@tfoote tfoote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a few comments inline on the range checking. And we should make sure to have unit tests for the range checking to validate that they're working.

bounds_check_duration_scale(int64_t dns, double scale, uint64_t max)
{
auto abs_dns = (uint64_t)std::abs(dns);
auto abs_scale = (uint64_t)std::abs(scale);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casting this to be an unsigned integer I think is going to do the wrong thing here. It's used lower as if it's still a float.

auto abs_scale = (uint64_t)std::abs(scale);

if ((abs_scale >= 1.0 && abs_dns > (uint64_t)(max / abs_scale)) ||
(abs_scale < 1.0 && (uint64_t)(abs_dns * abs_scale > max)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're below an absolute scaling factor of 1 the value can only get smaller which will never overflow or underflow a signed integer. I think this whole 2nd case can be dropped.

(abs_scale < 1.0 && (uint64_t)(abs_dns * abs_scale > max)))
{
if ((dns > 0 && scale > 0) || (dns < 0 && scale < 0)) {
throw std::overflow_error("addition leads to int64_t overflow");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be 'duration scaling' not 'addition'

if ((dns > 0 && scale > 0) || (dns < 0 && scale < 0)) {
throw std::overflow_error("addition leads to int64_t overflow");
} else {
throw std::underflow_error("addition leads to int64_t underflow");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be 'duration scaling' not 'addition'

@@ -54,6 +54,9 @@ TEST(TestDuration, operators) {
EXPECT_EQ(sub.nanoseconds(), (rcl_duration_value_t)(young.nanoseconds() - old.nanoseconds()));
EXPECT_EQ(sub, young - old);

rclcpp::Duration scale = old * 3;
EXPECT_EQ(scale.nanoseconds(), (rcl_duration_value_t)(old.nanoseconds() * 3));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also have tests for the underflow and overflow. In particular I'd like to see at least all 4 cases of underflow and overflow with positive and negative scaling factors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for comments, they are all reasonable.

@dirk-thomas
Copy link
Member

Please make sure to run the unit tests of the package locally. The linters will e.g. enforce to use C++ cast rather than C casts.

@tfoote tfoote dismissed their stale review February 16, 2018 08:55

updated code

@tfoote
Copy link
Contributor

tfoote commented Feb 21, 2018

CI:
Linux: Build Status
Linux arm64: Build Status
OSX: Build Status
Windows: Build Status

Copy link
Contributor

@tfoote tfoote left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows also failed with a gateway issue so i'm going to retrigger it.

bounds_check_duration_scale(int64_t dns, double scale, uint64_t max)
{
auto abs_dns = static_cast<uint64_t>(std::abs(dns));
auto abs_scale = std::abs(scale);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is apparently ambiguous on OSX: https://ci.ros2.org/job/ci_osx/3306/consoleFull

03:04:22 [ 38%] Building CXX object CMakeFiles/rclcpp.dir/src/rclcpp/contexts/default_context.cpp.o
03:04:23 [ 39%] Building CXX object CMakeFiles/rclcpp.dir/src/rclcpp/duration.cpp.o
03:04:23 /Users/osrf/jenkins/workspace/ci_osx/ws/src/ros2/rclcpp/rclcpp/src/rclcpp/duration.cpp:189:20: error: call to 'abs' is ambiguous
03:04:23   auto abs_scale = std::abs(scale);
03:04:23                    ^~~~~~~~
03:04:23 /usr/include/stdlib.h:137:6: note: candidate function
03:04:23 int      abs(int) __pure2;
03:04:23          ^
03:04:23 /Library/Developer/CommandLineTools/usr/include/c++/v1/stdlib.h:115:44: note: candidate function
03:04:23 inline _LIBCPP_INLINE_VISIBILITY long      abs(     long __x) _NOEXCEPT {return  labs(__x);}
03:04:23                                            ^
03:04:23 /Library/Developer/CommandLineTools/usr/include/c++/v1/stdlib.h:117:44: note: candidate function
03:04:23 inline _LIBCPP_INLINE_VISIBILITY long long abs(long long __x) _NOEXCEPT {return llabs(__x);}
03:04:23                                            ^
03:04:23 /Users/osrf/jenkins/workspace/ci_osx/ws/src/ros2/rclcpp/rclcpp/src/rclcpp/duration.cpp:203:13: error: no member named 'isnormal' in namespace 'std'
03:04:23   if (!std::isnormal(scale)) {
03:04:23        ~~~~~^
03:04:23 2 errors generated.
03:04:23 make[2]: *** [CMakeFiles/rclcpp.dir/build.make:212: CMakeFiles/rclcpp.dir/src/rclcpp/duration.cpp.o] Error 1
03:04:23 make[1]: *** [CMakeFiles/Makefile2:855: CMakeFiles/rclcpp.dir/all] Error 2
03:04:23 make: *** [Makefile:141: all] Error 2
03:04:23 

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though, it should probably work anyways...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might just need to #include <cmath>. The standard seems to have been inconsistent on that in the past, which would allow for two different implementations to give you different results.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll explicitly add #include , thank you

@dhood
Copy link
Member

dhood commented Feb 23, 2018

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

this->rcl_duration_.nanoseconds,
scale,
std::numeric_limits<rcl_duration_value_t>::max());
return Duration(rcl_duration_.nanoseconds * scale);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is giving a warning on windows: http://ci.ros2.org/job/ci_windows/4078/

'argument': conversion from 'double' to 'rcl_duration_value_t', possible loss of data

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess a explicit cast can avoid this warning, however locally I have no windows build environment, please help re-trigger CI to check.

@sloretz
Copy link
Contributor

sloretz commented Feb 27, 2018

CI with 3dacb27

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@jwang11
Copy link
Contributor Author

jwang11 commented Mar 6, 2018

Windows warning disappeared. From log, the failure on macOS and Windows are python test script to execute command, which should not relate to this PR.

Duration
Duration::operator*(double scale) const
{
if (!std::isnormal(scale)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tfoote is it appropriate to prevent users from having a scale of 0 here? Seems too strict

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, a zero scale value would be valid. I think isfinite would be a better check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, in theory zero is valid to scale although this operation is meaningless. Ok, I'll update code from isnormal to isfinite which allow both normal and zero.

jwang11 and others added 8 commits March 9, 2018 16:46
Duration scale is a convinient operation which had supported in ROS.
This commit make ROS2 support it.

Signed-off-by: jwang <jing.j.wang@intel.com>
Signed-off-by: jwang <jing.j.wang@intel.com>
*) Keep abs_scale double, not cast to uint64_t
*) drop unnecessary check under condition abs_scale < 1.0
*) Correct warning text
*) Add overflow/underflow test when do scaling

Signed-off-by: jwang <jing.j.wang@intel.com>
Signed-off-by: jwang <jing.j.wang@intel.com>
Signed-off-by: jwang <jing.j.wang@intel.com>
Signed-off-by: jwang <jing.j.wang@intel.com>
@jwang11
Copy link
Contributor Author

jwang11 commented Mar 16, 2018

If this PR is still under review by someone? Actually I have a porting work from ROS1 to ROS2 which reply on this patch, is it possible expedite the process? thanks

@tfoote
Copy link
Contributor

tfoote commented Mar 16, 2018

@jwang11 It's good to comment back when the existing reviewers comments are addressed so we know it's ready to look at again.

I've restarted CI:

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@tfoote
Copy link
Contributor

tfoote commented Mar 16, 2018

Unfortunately the branch was now out of date. I rebased it to https://github.com/ros2/rclcpp/tree/duration_scale

And started CI again.

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@tfoote
Copy link
Contributor

tfoote commented Mar 16, 2018

The only failures are composition 2 on osx and 4 on windows: ros2/build_farmer#86

@tfoote
Copy link
Contributor

tfoote commented Mar 16, 2018

Squashed rebased and merged in af6e86c

@tfoote tfoote closed this Mar 16, 2018
@tfoote tfoote removed the in review Waiting for review (Kanban column) label Mar 16, 2018
nnmm pushed a commit to ApexAI/rclcpp that referenced this pull request Jul 9, 2022
Signed-off-by: ivanpauno <ivanpauno@ekumenlabs.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants