Topic: You don't pay for what you don't use


Author: John_David_Galt@cup.portal.com
Date: 1996/07/19
Raw View
gustav@morpheus.compulink.co.uk (Paul Moore) says:

> My particular example (and the one which is probably key to most
> users) is the streams library. Consider the canonical "Hello, world"
> program. This can be written in a number of ways - varying from
> system-dependent use of the write() system call, through use of the C
> puts() or printf() functions, to the use of C++ cout. Ie,

> 1.  int main()
>     {
>         write(1,"Hello, world!\n",14);
>         return 0;
>     }

> 2.  int main()
>     {
>         puts("Hello, world!\n");
>         return 0;
>     }

> 3.  int main()
>     {
>         printf("Hello, world!\n");
>         return 0;
>     }

> 4.  int main()
>     {
>         cout << "Hello, world!\n";
>         return 0;
>     }

> In accordance with the above principle, all of these programs should
> "cost" the same (in terms of code size, execution time, ...)

This "ought to be" approximately true, except for the case using printf().
printf() has to be able to interpret its format string at run time, and deal
with any "%" sequences that might be there, so it is always going to be
bigger and slower than using write() or puts().  Indeed, I was taught that
the whole purpose of creating the iostream library was to let the compiler
interpret the "format" of your output at compile time, thus producing smaller
code.

However, it hasn't worked out that way in real life.  EVERY system I've seen
puts the whole iostream library (or at least all of each class) in one link
module, so example 4 pulls in all 40+ functions of class ostream and is a
much larger executable than example 3.  In fact, it's 200K on my DOS machine!

What we really need is a system smart enough to link in only those member
functions (and operators) which are actually called.  Until that happens, I'm
going to keep using stdio (possibly with my own "simplified iostream" wrapper
classes) rather than iostream in C++ code.

John David Galt
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: clamage@Eng.sun.com (Steve Clamage)
Date: 1996/07/19
Raw View
In article 18081@cup.portal.com, John_David_Galt@cup.portal.com writes:
>This "ought to be" approximately true, except for the case using printf().
>printf() has to be able to interpret its format string at run time, and deal
>with any "%" sequences that might be there, so it is always going to be
>bigger and slower than using write() or puts().  Indeed, I was taught that
>the whole purpose of creating the iostream library was to let the compiler
>interpret the "format" of your output at compile time, thus producing smaller
>code.

Whoever taught you that was misinformed. The purpose of IOstreams was and
is to provide type-safe, user-extensible I/O which gives the appearance
of being built into C++. You will note that C stdio does not provide
those capabilities.

I have never understood the obsession with measuring the size of a
"hello world" program. What does that tell you about real programs
in real life?


>However, it hasn't worked out that way in real life.  EVERY system I've seen
>puts the whole iostream library (or at least all of each class) in one link
>module, so example 4 pulls in all 40+ functions of class ostream and is a
>much larger executable than example 3.  In fact, it's 200K on my DOS machine!

IOstreams provides a framework for I/O. If you don't use any I/O, you
don't pay for any I/O. If you do use I/O, you drag in some amount of
library code, depending on the details of the implementation. Some
implementors have chosen to make the runtime library very fine-grained.
In that case, the "hello world" program will pull in a modest amount
of library code. On the other hand, the number of virtual functions
in the iostream class hierarchy means that with usual implementations
you will get a lot of stuff whether you use it or not. Finally, some
implementations don't bother trying to make the I/O library fine-grained;
if you use any I/O, you get nearly the whole thing.

Let's be clear on our goals. If you want to make the smallest possible
"hello world" program, don't use stdio or iostreams. Something like
 write(1, "Hello, world", 12);
works on most systems and pulls in essentially no I/O library, since
the "write" function is normally an operating system call.

Why don't you always write code like that? For the same reason you
program in a higher-level language instead of assembler. You want
more ease in reading, writing, and maintaining the code, and more
robustness under design and implementation changes. You are willing
to put up with runtime code which is larger and slower than the best
an expert could get with hand-crafted assembler.

If you have a tight memory budget, it might be that iostreams isn't
the way to go. Or you might want a specially-tailored version that
includes only the features you actually use. C++ implementations
for embedded systems commonly feature special versions of the C++
library which don't correspond exactly to the standard.

Outside the embedded-system world, it is increasingly common for the C++
runtime library to be a dynamically-linked library, a single copy being
shared by every C++ program running on the computer. In that case, the
incremental cost per program of the runtime library is very small, whether
the library is fine-grained or monolithic.
---
Steve Clamage, stephen.clamage@eng.sun.com




[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: gustav@morpheus.compulink.co.uk (Paul Moore)
Date: 1996/07/23
Raw View
John_David_Galt@cup.portal.com wrote:

>gustav@morpheus.compulink.co.uk (Paul Moore) says:
>
>>[... my huge posting...]
>
>This "ought to be" approximately true, except for the case using printf().
>printf() has to be able to interpret its format string at run time, and deal
>with any "%" sequences that might be there, so it is always going to be
>bigger and slower than using write() or puts().  Indeed, I was taught that
>the whole purpose of creating the iostream library was to let the compiler
>interpret the "format" of your output at compile time, thus producing smaller
>code.
>
>However, it hasn't worked out that way in real life.  EVERY system I've seen
>puts the whole iostream library (or at least all of each class) in one link
>module, so example 4 pulls in all 40+ functions of class ostream and is a
>much larger executable than example 3.  In fact, it's 200K on my DOS machine!
>
>What we really need is a system smart enough to link in only those member
>functions (and operators) which are actually called.  Until that happens, I'm
>going to keep using stdio (possibly with my own "simplified iostream" wrapper
>classes) rather than iostream in C++ code.
>
>John David Galt

That's what I thought :-(
It's a real problem. Iostreams are SO much better than C stdio, in
terms of type safety, extensibility, flexibility, readability,
elegance, etc, that the overhead is a disaster. Code bloat (IMHO) is a
serious evil.

Of course, shared libraries conspire to make this problem seem to go
away (it doesn't, of course...)

Gustav.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: paul.black@vf.vodafone.co.uk
Date: 1996/07/15
Raw View
gustav@morpheus.compulink.co.uk (Paul Moore) wrote:
> <snip>
> My particular example (and the one which is probably key to most
> users) is the streams library. Consider the canonical "Hello, world"
> program. This can be written in a number of ways - varying from
> system-dependent use of the write() system call, through use of the C
> puts() or printf() functions, to the use of C++ cout. Ie,
>
> 1.  int main()
>     {
>         write(1,"Hello, world!\n",14);
>         return 0;
>     }
>
> 2.  int main()
>     {
>         puts("Hello, world!\n");
>         return 0;
>     }
>
> 3.  int main()
>     {
>         printf("Hello, world!\n");
>         return 0;
>     }
>
> 4.  int main()
>     {
>         cout << "Hello, world!\n";
>         return 0;
>     }
>
> In accordance with the above principle, all of these programs should
> "cost" the same (in terms of code size, execution time, ...)
> <snip>

This is not true, whilst the four approaches used produce the same
output when executed, the execution time will not be the same.

The first case ought to be the most efficient - on Unix this is a direct
call to the operating system. The write() call also does not have to compute
the length of the string as this is supplied.

The other cases all have to calculate the string length before output
can be performed (possibly with a write()!) and can also perform
buffering of the output if so configured. The printf() case also has to ensure
that there are no '%' characters in the format string.

This is ignoring the efficiency of the library implementations so it
may be that iostreams will be slower than using the streams of printf()
and puts() - or vice versa.

Just because something looks the same, it doesn't mean it is the same.

Paul
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: gustav@morpheus.compulink.co.uk (Paul Moore)
Date: 1996/07/12
Raw View
In his "Design of C++" book, Bjarne Stroustrup made a particular point
of the idea that you should not pay for what you don't use in C++. It
seems that this principle was fairly key to him in the design of C++,
as a general-purpose language which could be used in a wide range of
application areas.

In his book, Bjarne didn't make any comments on the applicability of
this principle to library design (presumably because at the time the
book was written, the standard C++ library was not well enough
defined).

I would be interested to know whether the standard library has in fact
been checked against this principle in any way. Obviously, whether a
particular library implementation does so, is a quality of
implementation issue. However, I'm wondering whether anyone has tried
to confirm that the library functionality CAN be provided without
overhead.

My particular example (and the one which is probably key to most
users) is the streams library. Consider the canonical "Hello, world"
program. This can be written in a number of ways - varying from
system-dependent use of the write() system call, through use of the C
puts() or printf() functions, to the use of C++ cout. Ie,

1.  int main()
    {
        write(1,"Hello, world!\n",14);
        return 0;
    }

2.  int main()
    {
        puts("Hello, world!\n");
        return 0;
    }

3.  int main()
    {
        printf("Hello, world!\n");
        return 0;
    }

4.  int main()
    {
        cout << "Hello, world!\n";
        return 0;
    }

In accordance with the above principle, all of these programs should
"cost" the same (in terms of code size, execution time, ...)

I did some experiments with GNU C++ for DOS (DJGPP v2.0) and I found
that the first three came in at a code size of 45/50/55K (close enough
to no extra cost) whereas the final one came in at nearly 160K! While
one test is not enough to make a real judgement, my initial impression
is that streams are very expensive - a fact which could easily put me
off using them!

Before I start complaining about the GNU C++ implementation, I thought
I'd check here - should I be expecting the "don't pay for what you
don't use" principle to apply here?

(I guess one other possibility is that it is possible to implement the
CODE to support the principle, but it is difficult or impossible to
split the implementation into small enough chunks to allow a linker to
eliminate unused code - given current linker technology. Could this be
the case here?)

Thanks in advance for any comments,
Paul Moore.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: jkfields@texas.net (Jeff Fields)
Date: 1996/07/13
Raw View
gustav@morpheus.compulink.co.uk (Paul Moore) wrote:

>I did some experiments with GNU C++ for DOS (DJGPP v2.0) and I found
>that the first three came in at a code size of 45/50/55K (close enough
>to no extra cost) whereas the final one came in at nearly 160K! While
>one test is not enough to make a real judgement, my initial impression
>is that streams are very expensive - a fact which could easily put me
>off using them!

I tested using Borland C++ 4.02 and received similar results.  No 2
and 3 both came to 56.5K, while number 4 was only moderately fatter at
82.6K running under Windows95..


Jeff

"Why do they put braille characters on drive-up ATM machines?"
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: danm@zipnet.net (Dan Muller)
Date: 1996/07/14
Raw View
gustav@morpheus.compulink.co.uk (Paul Moore) wrote:
<snip>
>My particular example (and the one which is probably key to most
>users) is the streams library. Consider the canonical "Hello, world"
>program. This can be written in a number of ways - varying from
>system-dependent use of the write() system call, through use of the C
>puts() or printf() functions, to the use of C++ cout.
[...]
>In accordance with the above principle, all of these programs should
>"cost" the same (in terms of code size, execution time, ...)

<snip>

I don't think that everyone would agree with this assumption. Streams
have far more functionality, and if you use them at all, you can expect
to carry a certain amount of basic overhead. For small programs like
your examples, the power of streams are not needed, and hence the
overhead is probably not worth it.

That said, I do see the point that you're making, and I think that your
later comment about linker technology points to a part of the problem.
In general, it's a pity that C++ has carried the traditional
object/linker technology forward into large-scale and high-level OO
programming. Certainly this was an enabling factor in making C++ widely
available, but the more comprehensive system-building approach that
Eiffel seems to have taken sounds more forward-looking. How much
mixed-language programming do most of us do these days?