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

default RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED to 1 #169

Closed

Conversation

rotu
Copy link
Contributor

@rotu rotu commented Jul 13, 2019

Saner default logging behavior.
fixes #168

Signed-off-by: Dan Rose <dan@digilabs.io>
@rotu rotu force-pushed the line_buffer_stdout_by_default branch from b7b47a6 to b19b3af Compare July 13, 2019 19:31
Copy link
Member

@ivanpauno ivanpauno left a comment

Choose a reason for hiding this comment

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

Though I thing the changes are fine, IMO this is only a workaround to a bug in launch.
If you're launching multiple process with launch that don't use our logging macros, messages should be still in the correct order. We should maybe explore using PYTHONUNBUFFERED enviroment variable when running subprocesses ...

src/logging.c Outdated
if (strcmp(line_buffered, "1") == 0) {
g_force_stdout_line_buffered = true;
if (strcmp(line_buffered, "0") == 0) {
g_force_stdout_line_buffered = false;
} else if (strcmp(line_buffered, "0") != 0 && strcmp(line_buffered, "") != 0) {
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 should be:

} else if (strcmp(line_buffered, "1") != 0 && strcmp(line_buffered, "") != 0) {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops. Thank you!

Signed-off-by: Dan Rose <dan@digilabs.io>
@rotu
Copy link
Contributor Author

rotu commented Jul 15, 2019

Though I thing the changes are fine, IMO this is only a workaround to a bug in launch.

Fair. I think it's both. I wouldn't mind this PR being rejected so long as it was fixed in a different way.

If you're launching multiple process with launch that don't use our logging macros, messages should be still in the correct order. We should maybe explore using PYTHONUNBUFFERED enviroment variable when running subprocesses ...

A big part of the situation is splitting diagnostics over different streams. If I were writing my own logging, I would just log everything (even low-priority messages) over stderr, though I figure I would break something if I changed it here.

@ivanpauno
Copy link
Member

I will detail a little bit what the problem is: in linux (and probably mac), stdout is line buffered when associated with a terminal, if not it's fully buffered.
When launching sub-processes using launch, their stdout end up being fully buffered. So, the output isn't showed in the correct order. I haven't found a way of forcing the stdout of the subprocess to be line buffered with the python api (without using shell=True).

Other possible workarounds:

@ivanpauno
Copy link
Member

This is related to ros2/launch#188.

@dirk-thomas
Copy link
Member

I don't agree with the statement made in the original ticket:

The consequences of having RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED=1 when it should be 0 is a tiny (if noticeable) performance hit.

I doubt that the performance hit is actually tiny. When a program outputs frequent messages I would rather expect the performance hit to be fairly significant.

I understand that line buffering results in more convenient to read output but I expect this change to impact performance in an undesired way and therefore am hesitant to change it as is (especially without any further investigation into how it actually effects the performance).


Just one external article writing about the performance implications: https://eklitzke.org/stdout-buffering

@jacobperron
Copy link
Member

@dirk-thomas beat me to it.

This was the same reason for defaulting to 0 in rosconsole (where this logic was copied from).

@dirk-thomas dirk-thomas added the invalid This doesn't seem right label Jul 15, 2019
@rotu
Copy link
Contributor Author

rotu commented Jul 15, 2019

I doubt that the performance hit is actually tiny. When a program outputs frequent messages I would rather expect the performance hit to be fairly significant.

@dirk-thomas, I tested it. It's not a significant performance hit, and to notice it, you'd have to be doing a truly massive amount of logging (the 10k messages in the below examples amount to 2.3 MB of log output). For reference, 100k calls to rclcpp::spin have an overhead of 3.668 seconds.

Line buffering off:

RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED=0
ros2 run logperf main > /dev/null
Did 100000 messages in 0.250194 seconds
ros2 run logperf main
# ...
Did 100000 messages in 0.615212 seconds
ros2 run logperf main > outfile.txt  
Did 100000 messages in 0.290205 seconds

Line buffering on:

RCUTILS_CONSOLE_STDOUT_LINE_BUFFERED=1
ros2 run logperf main > /dev/null
Did 100000 messages in 0.290174 seconds
ros2 run logperf main
# ...
Did 100000 messages in 0.613463 seconds
ros2 run logperf main > outfile.txt   
Did 100000 messages in 0.489006 seconds

Code:

#include <chrono>
#include "rclcpp/rclcpp.hpp"
int main(int argc, char * argv[])
{
  size_t count = 100000;
  rclcpp::init(argc, argv);
  rclcpp::Node n("main");
  auto t0 = n.now();
  for (int i = 0; i < count; i++) RCLCPP_INFO(n.get_logger(), "logging");
  auto t1 = n.now();

  std::cerr << "Did " << count << " messages in " << (t1 - t0).seconds() << " seconds";
}

@dirk-thomas
Copy link
Member

The default for buffering of non-interactive terminals is fully buffered. We won't be changing that default since the reason for that default in C as well as Python is performance. While some slowdown might be acceptable in many cases we don't think it should be the default.

That being said we happy to make changing the default - either for a specific program or from a launch file - as easy and convenient as possible. Demos / tutorials should explicitly use these options if immediate flushing is desired.

Since the current state of the PR changes the default I will go ahead and close it.

@rotu
Copy link
Contributor Author

rotu commented Jul 20, 2019

Makes sense. I don’t think this is quite the right fix anymore anyway ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid This doesn't seem right
Projects
None yet
Development

Successfully merging this pull request may close these issues.

INFO and ERROR logging should come out in order by default
4 participants