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

Add SimpleCarState Splitter #511

Merged
merged 4 commits into from
Jul 26, 2018

Conversation

apojomovsky
Copy link

Fixes #504

  • This PR adds a new drake system that, splits the vectorized SimpleCarState_v into individual SimpleCarState messages, one for each agent.
  • Since the whole vector of states is evaluated each time one of the individual states is requested, an initial negative performance impact was expected.
  • Nonetheless, the use of the caching feature found in this experimental branch in drake helps us to reduce the impact to a minimum, which is expected since the successive calls to the EvalInputPort method by each of the different state outputs would not require a whole recalculation of the vector.
  • As shown in the performance analysis below, the use of caching allows us to tremendously reduce the time to complete an instance of the delphyne-mobil-perf demo with 20 MOBIL cars, although the attention should focus in the relative times:
    • With the caching feature disabled (master) we get a negative impact of about 17% in the time to complete the test.
    • Whereas with the caching feature enabled this negative impact gets reduced to about 10%.
    • In both cases, reducing the publish rate to 10 Hz reduces this impact to about 4% for both cases (maybe we could get better results with longer tests, I can do them if necessary).

screenshot from 2018-07-19 15-30-27

Copy link
Contributor

@hidmic hidmic left a comment

Choose a reason for hiding this comment

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

@apojomovsky Left some comments!


for (int i = 0; i < num_agents; ++i) {
// Appends an ignition publisher to the vector for each agent.
agent_state_vector.push_back(
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky why keeping a vector of pointers, as opposed to just using the returned reference on each loop iteration and then dropping it?

Copy link
Author

Choose a reason for hiding this comment

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

true that! done, thanks!

namespace delphyne {

using std::placeholders::_1;
using std::placeholders::_2;
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky consider placing these using ... statements closer to where they're being used (i.e. outside the loop but within the constructor).

Copy link
Author

Choose a reason for hiding this comment

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

done, thanks!

using std::placeholders::_2;

SimpleCarState_v_Splitter::SimpleCarState_v_Splitter(int agents_number) {
DeclareAbstractInputPort();
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky should we validate agents_number > 0?

Copy link
Author

Choose a reason for hiding this comment

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

sounds good. done, thanks!


for (int i = 0; i < agents_number; ++i) {
auto f = std::bind(&SimpleCarState_v_Splitter::DoSplit, this, _1, _2, i);
auto d = std::bind(&SimpleCarState_v_Splitter::DoAlloc, this);
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky consider taking d outside the loop, we can reuse it for every output port.

Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky also, consider giving both functors a more descriptive name.

Copy link
Author

Choose a reason for hiding this comment

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

done, thanks!


std::unique_ptr<drake::systems::AbstractValue>
SimpleCarState_v_Splitter::DoAlloc() {
return drake::systems::AbstractValue::Make(ignition::msgs::SimpleCarState{});
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky consider having an ignition::msgs::SimpleCarState model_; instead of instantiating a temporary one each time.

Copy link
Author

Choose a reason for hiding this comment

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

done, thanks!


// Assigns the state returned by the agent_index to the output.
auto& valor = output->GetMutableValue<ignition::msgs::SimpleCarState>();
if (simple_car_state_v.states_size() >= agent_index) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky I wonder if we should let this pass by silently, as opposed to blowing up if it doesn't hold. Are we expecting transient variations here?

Copy link
Author

Choose a reason for hiding this comment

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

just added a validation that throws an exception if the condition is not met

drake::systems::AbstractValue* output, int agent_index) const;

/// @brief Allocates an abstract value object.
std::unique_ptr<drake::systems::AbstractValue> DoAlloc();
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky can be const?

Copy link
Author

Choose a reason for hiding this comment

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

done, thanks!

/// @brief Sets the output value with the SimpleCarState message that's at the
/// given index of the SimpleCarState_v.
/// @param[in] context The simulation context.
/// @param[in] output A pointer to an abstracted SimpleCarState message.
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky missing agent_index argument in documentation. Also, a bit of an explanation as to why its signature is different from that of all other output ports' Calc functions is in order.

Copy link
Author

Choose a reason for hiding this comment

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

done, thanks!

@@ -19,7 +19,6 @@ awscli
curl
git
libignition-cmake-dev
libsqlite3-dev
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky what happened here?

Copy link
Author

Choose a reason for hiding this comment

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

Hm, a commit from another PR. Just rebased my branch with master so that this doesn't appear anymore here.


/// @brief A system that takes a SimpleCarState_V and splits it into separate
/// SimpleCarState messages.
class SimpleCarState_v_Splitter : public drake::systems::LeafSystem<double> {
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky consider making this a template: double -> T.

It's funny though, we need the scalar for this system to operate on a simulation but it doesn't use it. I wonder if there're examples of this already in Drake.

Copy link
Author

Choose a reason for hiding this comment

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

done, thanks!

@apojomovsky apojomovsky force-pushed the apojomovsky/simple_car_state_splitter branch 4 times, most recently from 0ec6745 to 8fc2127 Compare July 20, 2018 20:00
@apojomovsky
Copy link
Author

Thanks for the review @hidmic , I just finished addressing your comments. PTAL.

@apojomovsky apojomovsky force-pushed the apojomovsky/simple_car_state_splitter branch from 8fc2127 to 3d58710 Compare July 20, 2018 20:12
@apojomovsky apojomovsky force-pushed the apojomovsky/simple_car_state_splitter branch from 3d58710 to 04eaf31 Compare July 20, 2018 20:23
Copy link
Contributor

@clalancette clalancette left a comment

Choose a reason for hiding this comment

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

A few mostly minor things here.

@@ -1,5 +1,7 @@
// Copyright 2017 Toyota Research Institute

#include "backend/automotive_simulator.h"

#include <algorithm>
#include <functional>
#include <utility>
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: #include <string>

Copy link
Author

Choose a reason for hiding this comment

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

done, thanks!

builder_
->template AddSystem<AgentsStatePublisherSystem>(
std::make_unique<AgentsStatePublisherSystem>(
"agent/" + std::to_string(i + 1) + "/state"))
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, kind of gross. Internally the agents are 0-based; are we sure we want them 1-based to the external observer?

Copy link
Author

Choose a reason for hiding this comment

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

You're right. This change came from the index number that the PoseBundle to SimpleCarState_V was taking, that was 1-based (my mistake at that point), now changed it there and here to be 0-based again.

@@ -26,6 +27,7 @@ target_link_libraries(translations
protobuf_messages
${drake_LIBRARIES}
${IGNITION-COMMON_LIBRARIES}
ignition-msgs2::ignition-msgs2
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor, but we mostly are using ${IGNITION-MSGS_LIBRARIES} in the code (the one exception is https://github.com/ToyotaResearchInstitute/delphyne/blob/master/test/regression/cpp/CMakeLists.txt#L24, which we should probably change to be consistent).

Copy link
Author

Choose a reason for hiding this comment

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

Restored it for now, although we'll be changing to the library::library format after #507

namespace delphyne {

template <typename T>
SimpleCarState_v_Splitter<T>::SimpleCarState_v_Splitter(int agents_number) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Personally I think num_agents describes the situation better (agents_number could possibly be confused for the number of an agent, which this is not).

Copy link
Author

Choose a reason for hiding this comment

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

Totally agree, just did that. thanks!

splitter->get_input_port(0));

for (int i = 0; i < num_agents; ++i) {
// Appends an ignition publisher to the vector for each agent.
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this really do an append? It kind of just looks like it Connects the SimpleCarState_v to the Splitter, but I'm not sure. Could you clarify this comment a bit?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, it adds a new system to the builder on each iteration and connects it to the splitter.
That being said, I just replaced the previous comment block with a more cleared explanation.

@apojomovsky
Copy link
Author

Thanks for the review @clalancette . Just finished addressing your comments. PTAL

Copy link
Contributor

@hidmic hidmic left a comment

Choose a reason for hiding this comment

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

Couple comments @apojomovsky, but it looks great for the most part! 👍

// Assigns the state returned by the agent_index to the output.
auto& mutable_state =
output->GetMutableValue<ignition::msgs::SimpleCarState>();
if (simple_car_state_v.states_size() >= agent_index) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky shouldn't be > instead of >=?

Copy link
Author

Choose a reason for hiding this comment

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

You're right, thanks! Done.

///
/// In contrast to typical system's `Calc` methods, the presence of an extra
/// argument in this function's signature comes from the need to specify which
/// of the vector element must be used to generate the output.
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky consider ...of the vector element... -> ...of the vector elements....

Copy link
Author

Choose a reason for hiding this comment

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

Done, thanks!

/// @brief Allocates an abstract value object.
std::unique_ptr<drake::systems::AbstractValue> DoAlloc() const;

ignition::msgs::SimpleCarState state_;
Copy link
Contributor

Choose a reason for hiding this comment

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

@apojomovsky missing documentation.

Copy link
Author

Choose a reason for hiding this comment

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

Oops, just added it. thanks!

Copy link
Contributor

@clalancette clalancette left a comment

Choose a reason for hiding this comment

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

This looks good to me, except for the one point about > vs >= that @hidmic brought up. Once that is fixed/clarified, I'm happy to approve.

@apojomovsky
Copy link
Author

An updated table including the results of testing the splitter with subscribers (in this case, by enabling the GUI). Based on these results, the impact of adding a splitter with reduced update rate of 10Hz has a negative performance hit of about 2%

screenshot from 2018-07-26 16-03-21

@apojomovsky
Copy link
Author

Should we leave the publish rate in default or maybe reduce it to 10Hz or so? @clalancette @hidmic

@clalancette
Copy link
Contributor

Should we leave the publish rate in default or maybe reduce it to 10Hz or so? @clalancette @hidmic

My opinion is that we should merge this as-is, and then open a separate issue/PR to address the publishing rate (as it may have knock-on effects, I'm not sure). But I could be convinced otherwise.

@hidmic
Copy link
Contributor

hidmic commented Jul 26, 2018

Agree with @clalancette. This one is ready to go.

@apojomovsky
Copy link
Author

Thanks guys! Merging...

@apojomovsky apojomovsky merged commit e189962 into master Jul 26, 2018
@apojomovsky apojomovsky deleted the apojomovsky/simple_car_state_splitter branch July 26, 2018 19:38
@stonier stonier mentioned this pull request Sep 18, 2018
14 tasks
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.

3 participants