Old DOUT

What replaced the old DOUT?

I'm working on sending debug code upstream and one of the things I
want to add is circular buffering for debug output. This is a real
help when processing large files.

So I need a stream that can act differently than errs(). Should I just
create one?

                               -Dave

What replaced the old DOUT?

DEBUG({
  errs() << ...;
);

- Daniel

Hello, David

What replaced the old DOUT?

DEBUG(errs() << foo);

The reason is quite simple - DOUT in release mode was just /dev/null,
but the functions sending data to it were still called.

errs() is no good. I would want to keep errs() printing things out
immediately. I need something else that buffers until program termination.

So I would write the above as:

DEBUG(dbgs() << foo);

Does that sound reasonable?

There are some tricky cases where dump routines are used either to
print error messages or to print debug information. In those cases
I may have to parameterize the dump routine with the stream.

                            -Dave

Hello, David

What replaced the old DOUT?

DEBUG(errs() << foo);

The reason is quite simple - DOUT in release mode was just /dev/null,
but the functions sending data to it were still called.

errs() is no good. I would want to keep errs() printing things out
immediately. I need something else that buffers until program termination.

So I would write the above as:

DEBUG(dbgs() << foo);

Does that sound reasonable?

If you're asking if a new dbgs() might be useful, "yes if specified well". If you're asking if you can convert everything to using it, "no".

There are some tricky cases where dump routines are used either to
print error messages or to print debug information. In those cases
I may have to parameterize the dump routine with the stream.

What do you mean?

-Chris

> So I would write the above as:
>
> DEBUG(dbgs() << foo);
>
> Does that sound reasonable?

If you're asking if a new dbgs() might be useful, "yes if specified well".
If you're asking if you can convert everything to using it, "no".

I'm not sure what you mean here. It's not ok to convert code under DEBUG() or
#ifndef NDEBUG to use dbgs()? Then what's the point of providing it?

My intent is to have dbgs() == errs() when debug mode is disabled.

> There are some tricky cases where dump routines are used either to
> print error messages or to print debug information. In those cases
> I may have to parameterize the dump routine with the stream.

What do you mean?

For example, SDNode::dump() is used to both print out debug information
and to do dumps in error context (cannot select, etc.).

One option is to make the signature SDNode::dump(raw_ostream &) or create
a new overload.

Another option is to have SDNode::dump() use dbgs() and when debugging is
off, dbgs() == errs(). Of course, when debugging is on, error dumps will
go to the debug stream, which actually isn't the worst thing in the world,
especially if you have a huge source input and are using the (new)
circular-buffering raw_ostream to capture the last N bytes of stream output.

                              -Dave

If you're asking if a new dbgs() might be useful, "yes if specified well".
If you're asking if you can convert everything to using it, "no".

I'm not sure what you mean here. It's not ok to convert code under DEBUG() or
#ifndef NDEBUG to use dbgs()?

Right.

Then what's the point of providing it?

I don't know what dbgs does, so I don't know!

My intent is to have dbgs() == errs() when debug mode is disabled.

Do you know why DOUT was removed? The problem is that things like this:

DOUT << foo();

evaluate foo even when assertions are disabled. This is bad, and bringing it back with a new name is not good.

There are some tricky cases where dump routines are used either to
print error messages or to print debug information. In those cases
I may have to parameterize the dump routine with the stream.

What do you mean?

For example, SDNode::dump() is used to both print out debug information
and to do dumps in error context (cannot select, etc.).

One option is to make the signature SDNode::dump(raw_ostream &) or create
a new overload.

The normal pattern is to define print(raw_ostream&) and have dump() call print(errs()).

-Chris

Can't you just write a separate tool to handle this? "less -B" might even be good enough for some purposes....

Can't you just write a separate tool to handle this? "less -B" might even be good enough for some purposes....

Printing to file / pipe is painfully slow. Grab some non-trivial .bc
and feed it via llc -debug - you can easily wait for several dozen
minutes until it will finish.

Yep. Buffering like this greatly speeds up the debug cycle.

We see codes with hundreds of thousands of lines and tens of
thousands of loops. In a single function.

                             -Dave

=

I'm not sure what you mean here. It's not ok to convert code under
DEBUG() or #ifndef NDEBUG to use dbgs()?

Right.

Then what's the point of providing it?

I don't know what dbgs does, so I don't know!

dbgs() will be a circular-buffering raw_ostream, meaning it saves
the last N bytes (N == unlimited by default) and displays the
output at program termination if requested. By default output
gets generated immediately, just like errs().

I will add a flag -debug-buffer-size=N to set the buffer and turn
on delayed output. This is super useful when trying to debug
very large codes. I have had debug output consume GBs of disk space.
This avoids that problem but it only works if all current debug
output goes to the new stream.

As I said, by default there is no change in behavior. dbgs() works
very similarly to the formatted_raw_ostream in that it uses errs()
underneath to do the actual output and only does the circular buffering
and delayed output if requested.

It seems like there is better ways to handle this (i.e. split the input into smaller chunks) but I'm not opposed to the general idea.

The problem is that things like this:

DOUT << foo();

evaluate foo even when assertions are disabled. This is bad, and bringing
it back with a new name is not good.

That's not what I'm proposing.

DOUT << foo();

is broken. It should have been written as:

DEBUG(DOUT << foo());

Today we use:

DEBUG(errs() << foo());

With dbgs() it will be:

DEBUG(dbgs() << foo());

The only functional difference is the ability to use circular buffering.

Ok, I'm fine with that.

-Chris

> As I said, by default there is no change in behavior. dbgs() works
> very similarly to the formatted_raw_ostream in that it uses errs()
> underneath to do the actual output and only does the circular buffering
> and delayed output if requested.

It seems like there is better ways to handle this (i.e. split the input
into smaller chunks) but I'm not opposed to the general idea.

That's a lot of manual work. It's really not easy to do when the code is
all in one function.

> With dbgs() it will be:
>
> DEBUG(dbgs() << foo());
>
> The only functional difference is the ability to use circular buffering.

Ok, I'm fine with that.

Ok, I'll have a patch shortly.

                               -Dave