Discussion:
Size of linked program increasing with new version of GNAT.
(too old to reply)
Tony
2014-12-25 17:44:21 UTC
Permalink
I just downloaded the latest version of GNAT GPL. My previous version was 3.15p. I notice that the size of linked executables increase substantially. The minimal Hello-World program goes up in size from 67 to 195 KB.

Why? I would expect things to improve with newer versions instead of becoming worse.
Björn Lundin
2014-12-25 17:57:35 UTC
Permalink
Post by Tony
I just downloaded the latest version of GNAT GPL. My previous version was 3.15p. I notice that the size of linked executables increase substantially. The minimal Hello-World program goes up in size from 67 to 195 KB.
Why? I would expect things to improve with newer versions instead of becoming worse.
You just defined better to equal smaller executables.
Perhaps there are other wins?

Like supporting Ada05 and Ada12
Like producing better/more accurate crashdumps


It would help to state OS. And compiler/link flags
And architechture (32/64)
eventhough I guess 32 bit Win xp - or windows 2000.
That is OS on par age-wise wiht 3.15p - Or Win 98 ?

--
Björn
t***@tele2.se
2014-12-25 18:36:55 UTC
Permalink
Post by Björn Lundin
Perhaps there are other wins?
Yes, some programs run a bit faster (up to 25%).
Post by Björn Lundin
It would help to state OS. And compiler/link flags
And architecture (32/64)
eventhough I guess 32 bit Win xp - or windows 2000.
Thats right: 32 bit Win XP.
Compiled it with: gnatmake -O2 -largs -s
Björn Lundin
2014-12-25 19:41:22 UTC
Permalink
Post by t***@tele2.se
Post by Björn Lundin
Perhaps there are other wins?
Yes, some programs run a bit faster (up to 25%).
Post by Björn Lundin
It would help to state OS. And compiler/link flags
And architecture (32/64)
eventhough I guess 32 bit Win xp - or windows 2000.
Thats right: 32 bit Win XP.
Compiled it with: gnatmake -O2 -largs -s
I think you want -O1

-O1 for small size
-O2 for speed

I _think_

read more in the gnat users manual.
--
--
Björn
Shark8
2014-12-25 20:04:13 UTC
Permalink
Post by Björn Lundin
I think you want -O1
-O1 for small size
-O2 for speed
I _think_
read more in the gnat users manual.
-OS for small size.

See:
https://gcc.gnu.org/onlinedocs/gnat_ugn/Optimization-Levels.html#Optimization-Levels
t***@tele2.se
2014-12-25 20:15:22 UTC
Permalink
Post by Björn Lundin
I think you want -O1
-O1 for small size
-O2 for speed
I tried both combinations with both GNAT versions. The -O1/O2 switches makes no difference on the size. The object code of the main program is less than one KB, so most of the linked program must come from some precompiled library, which is not affected by the compiler switches.
Post by Björn Lundin
-Os for small size.
Tried this one also now. The 3.15p GNAT don't have it. The 2014 GNAT still produces a 195 KB executable.
Shark8
2014-12-25 21:23:23 UTC
Permalink
Post by t***@tele2.se
Post by Björn Lundin
I think you want -O1
-O1 for small size
-O2 for speed
I tried both combinations with both GNAT versions.
The -O1/O2 switches makes no difference on the size.
The object code of the main program is less than one KB, so most of the
linked program must come from some precompiled library, which is not
affected by the compiler switches.
Right.
Which means you'd have to compile all the other stuff, presumably w/ the
-Os switch. -- Probably with the "list possible restrictions" active,
and applying those restrictions as much as possible.
Post by t***@tele2.se
Post by Björn Lundin
-Os for small size.
Tried this one also now. The 3.15p GNAT don't have it. The 2014 GNAT
still produces a 195 KB executable.
Did you use the "strip unused sections" [or something similar] option
for the linker?
Peter Chapin
2014-12-25 22:48:22 UTC
Permalink
Post by Shark8
Post by t***@tele2.se
Post by Björn Lundin
-Os for small size.
Tried this one also now. The 3.15p GNAT don't have it. The 2014 GNAT
still produces a 195 KB executable.
Did you use the "strip unused sections" [or something similar] option
for the linker?
The OP might also want to look into gnatelim to see if using it could help
eliminate unusued code.

One could argue that the size of the "Hello, World" program isn't all that
important. The overhead might be large but if most of that overheard is
actually used in a realistically sized program, well, it's not really
overhead in that case.

Peter
Randy Brukardt
2014-12-27 01:39:14 UTC
Permalink
Post by Peter Chapin
Post by t***@tele2.se
Post by Björn Lundin
-Os for small size.
Tried this one also now. The 3.15p GNAT don't have it. The 2014 GNAT
still produces a 195 KB executable.
Did you use the "strip unused sections" [or something similar] option for
the linker?
The OP might also want to look into gnatelim to see if using it could help
eliminate unusued code.
I would guess this is the "problem". Janus/Ada does this automatically
(indeed, the Windows version doesn't even work without using it). Janus/Ada
also avoids any tasking overhead in programs that don't declare a task. But
Janus/Ada was designed for small program sizes; that's rarely a concern
today.
Post by Peter Chapin
One could argue that the size of the "Hello, World" program isn't all that
important. The overhead might be large but if most of that overheard is
actually used in a realistically sized program, well, it's not really
overhead in that case.
Right. We used to use that argument when people complained about the 8K
"Hello World" for Ada compared to some much smaller size for some other
language that was less safe.

But these days, I don't try to argue about it much. Trivia that isn't
related to one's uses of Ada is irrelevant, and the sorts of engineers that
gravitate to power tools like Ada (and thus are the real customers for Ada)
know not to care too much about irrelevant things. The people that worry too
much about such things tend not to stick with Ada anyway, so spending too
much effort discussing that isn't worth it.

Randy.
Simon Wright
2014-12-27 06:43:14 UTC
Permalink
Janus/Ada also avoids any tasking overhead in programs that don't
declare a task.
GNAT does this too.

A main program with a null body, compiled with -O2 and stripped,
resulted in executable size 83540; replacing the 'null;' by 'delay 0.0'
raised that to 107116.
Tony
2014-12-27 18:25:46 UTC
Permalink
Post by Simon Wright
A main program with a null body, compiled with -O2 and stripped,
resulted in executable size 83540;
I'd expect that program to be compiled into a single machine code return instruction.

I managed to create a 12 KB version of Hello-World, by excluding runtime and Ada.Text_Io and calling Win32 functions directly:

pragma No_Run_Time;
with System;
procedure Hello is

function Writeconsole
(Hconsoleoutput : Integer;
Lpbuffer : System.Address;
Nnumberofcharstowrite : Integer;
Lpnumberofcharswritten : Integer;
Lpreserved : Integer) return Integer;

pragma Import (Stdcall, Writeconsole, "WriteConsoleA");

function Getstdhandle (Nstdhandle : Integer) return Integer;

pragma Import (Stdcall, Getstdhandle, "GetStdHandle");

Std_Output_Handle : constant := -11;

S : constant String := "Hello, World!" & Ascii.Lf;
Dummy : Integer;

begin
Dummy := Writeconsole(Getstdhandle(Std_Output_Handle), S'Address, S'Length, 0, 0);
end;
Simon Wright
2014-12-27 23:18:45 UTC
Permalink
Post by Tony
I'd expect that program to be compiled into a single machine code return instruction.
And I expect it was.

A program's startup/shutdown code is likely to be pretty independent of
waht the program actually does, and will have a certain minimum size
appropriate to the platform. GNAT's minimum size depends on whether
tasking is involved or not.
Randy Brukardt
2014-12-29 23:56:42 UTC
Permalink
Post by Tony
Post by Simon Wright
A main program with a null body, compiled with -O2 and stripped,
resulted in executable size 83540;
I'd expect that program to be compiled into a single machine code return instruction.
I managed to create a 12 KB version of Hello-World, by excluding runtime
and
So what?

(1) I created a 56KB executable by using Janus/Ada on a simple Hello world
program using Text_IO. (Options: /zt/f).

(2) I could shrink that further to 38K by using RRText_IO instead of
Text_IO. (Text_IO has lots of overhead from maintaining line and column
counts that are almost never used; RRText_IO originated in our early CP/M
compilers [the ones that had to run in 48K RAM - code and data] and is
simpler but still has most of the useful capabilities.)

(3) But still, who cares? Im my experience with a variety of Ada compilers,
there's no correlation between the minimum size of a program and the size of
real programs. And programs that don't use at least some of exceptions,
controlled types, tasks, floating point, images, and other expensive
operations are hardly using Ada at all. The size of Hello world tells one
very little about the size and efficiency of a real program.

Randy.
Björn Lundin
2014-12-30 15:21:14 UTC
Permalink
Post by Randy Brukardt
But still, who cares? Im my experience with a variety of Ada compilers,
there's no correlation between the minimum size of a program and the size of
real programs.
Indeed. For databases, the equivalent test is

'select count('a') from some_table;'

It is not very useful as a measurement either,
some dbs actually traverse the table,
and some has a cached counter.

But what you really want is good performance
(whatever that is) for real applications,
not a constructed example that has little or no relevance.


--
Björn
Tony
2014-12-30 17:45:40 UTC
Permalink
Post by Randy Brukardt
The size of Hello world tells one
very little about the size and efficiency of a real program.
I have written about 600 Ada programs at home. The average size of the programs are 75 lines of code. I never use tasks. These are my real programs.
Randy Brukardt
2014-12-30 21:58:57 UTC
Permalink
Post by Tony
Post by Randy Brukardt
The size of Hello world tells one
very little about the size and efficiency of a real program.
I have written about 600 Ada programs at home. The average size of the
programs are 75 lines of code.
I never use tasks. These are my real programs.
Really? I'm skeptical that you can do anything useful in 75 lines of code.
After all, you can't even open a file properly in 75 lines of code. (That
is, getting the name from the user or the command line, and with appropriate
error handling.) About all you can do in that size is write a throw-away
program, and by definition, one doesn't care too much about the "goodness"
of the result of a throw-away program. (Plus, you're depending on the
implementation-defined error handling in that case -- and that's hardly
going to be free.)

If you are "with"ing a bunch of library packages to and using them in the 75
lines, your real program size has to count the size of the libraries that
you "with". Which is going to be a lot more than 75 lines.
Post by Tony
"I never use tasks."
Which eliminates ONE form of overhead. But one cannot (sensibly) write an
Ada program that doesn't use exceptions (from implicit checks if nothing
else - and you need the unhandled exception mechanisms); finalization is
used by many of the language-defined packages; virtually every program needs
the default storage pool; and so on.

Sigh. Why I am I feeding the troll here? Gosh knows.

Randy.


Randy.
Shark8
2014-12-30 23:51:53 UTC
Permalink
Post by Randy Brukardt
Sigh. Why I am I feeding the troll here? Gosh knows.
To fatten him up?
Jean François Martinez
2014-12-31 12:08:13 UTC
Permalink
On Tuesday, December 30, 2014 12:56:43 AM UTC+1, Randy Brukardt wrote:
The size of Hello world tells one
Post by Randy Brukardt
very little about the size and efficiency of a real program.
Trying to bring some common sense in the discussion (not fr(om you Mr Brukardt)

If we intend is to measure the actual quality of the compiler at generating small code then the significtaive variable is the size of the .o file not the size of the executable. The executable is parasited by things like runtime, libraries, dynamic linker (or first stage of dynamic linker) and so on. So the more capable your environment and the biggest the program.

So if the program is small and will run it on a half decent box you don't care. Remember the EEPC, that five years old laptop good for web surfing and little more? It had 1G of memory. A million Ks. So who cares about the size of hello world?

If your program has megs and megs of code then the overhead due to a more capable runtime will be completely irrelevant respective to the "pure" (that is .o) size of your program and third party (ie not related to Gnat) libraries.

If you have to squeeze your program on an Arduino then size matters but the maintainer of Gnat for Arduino has tuned the compiler default restrictions (gnat.adc), runtime and Gnat related libraries for small size so you can't draw conclusions basing on what you see on x86. Still more irrelevant because it is different machine code thus a different code generator so a bigger .o on X86 does not necessarily translate on a bigger .o on Arduino.

Just my 2c

Jean-François Martinez
Dmitry A. Kazakov
2014-12-31 12:45:59 UTC
Permalink
Post by Jean François Martinez
If we intend is to measure the actual quality of the compiler at
generating small code then the significtaive variable is the size of the
.o file not the size of the executable.
I remember a FORTRAN-IV compiler that generated direct and indirect code.
The latter was kind of interpreted, each code "instruction" was a jump to a
short subprogram implementing the semantics. The direct code was twice as
large than the indirect one and 50% faster. So, no, the size of object
files tells nothing.
Post by Jean François Martinez
The executable is parasited by
things like runtime, libraries, dynamic linker (or first stage of dynamic
linker) and so on.
The code size can be approximated by a linear function A + B*x, where x is
the program "complexity". Arguments that A might be irrelevant is true only
if B is correspondingly small compared to the alternatives so that with
growing x you could compensate your losses on A.

Regarding GNAT, I doubt that B is really small, especially if generics are
actively used, and A is substantially big has we all know.
Post by Jean François Martinez
So the more capable your environment and the biggest the program.
Which should be the opposite, actually, since you could get some
functionality from for the environment.

The problem is that the ratio capability/useless-garbage is quite low in
modern environments and the trend is that it rapidly nears zero.
Post by Jean François Martinez
So if the program is small and will run it on a half decent box you don't
care. Remember the EEPC, that five years old laptop good for web surfing
and little more? It had 1G of memory. A million Ks. So who cares about
the size of hello world?
The empiric law of SW teaches us that any resource available will be
consumed. A more specialized law, which is a consequence of the former, is:
Windows is here to make i486 out of any i7.
Post by Jean François Martinez
If your program has megs and megs of code then the overhead due to a more
capable runtime will be completely irrelevant respective to the "pure"
(that is .o) size of your program and third party (ie not related to Gnat)
libraries.
Which code must be linked dynamically or else, on the systems without
virtual memory, loaded into to RAM. Thus large A usually directly
translates into longer starting times. The effect we all know, each new
system, each new version takes 20% more time to start.

The time a program needed to start is a good estimation of the product line
age. E.g. compare start times of:

Borland C++
MS Visual Studio
AdaCore GPS
--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
Georg Bauhaus
2015-01-01 12:28:34 UTC
Permalink
Post by Dmitry A. Kazakov
Post by Jean François Martinez
The executable is parasited by
things like runtime, libraries, dynamic linker (or first stage of dynamic
linker) and so on.
The code size can be approximated by a linear function A + B*x, where x is
the program "complexity". Arguments that A might be irrelevant is true only
if B is correspondingly small compared to the alternatives so that with
growing x you could compensate your losses on A.
Executables' size also reflects technical needs: compressing an
executable program such as gnatmake shows ratios of
over one half on Intel. Chances are, then, that there is redundant
executable code in gnatmake. But there are reasons that there is,
I guess, because the optimizers make the processor perform better,
reflecting its sets of instructions and its architecture (parallel
pipelines etc.). When TIME is more important than SPACE
in order to meet timing requirements, greater code size might
seem paradoxical, but might be necessary.

Has anyone tried deduplication with executables?

Pascal Obry
2014-12-26 14:32:47 UTC
Permalink
Post by Tony
Why? I would expect things to improve with newer versions instead of becoming worse.
Nothing is becoming worse you are just looking at different things.

What about the debug info?

Which compiler options have you used?

Have your used inlining?

Since when "bigger size" means worse?

Have you looked at the actual code size (.text section)?

Have you benchmarked the actual code speed?

What is the price of the disk today compared to 10 years ago?

...
--
Pascal Obry / Magny Les Hameaux (78)

The best way to travel is by means of imagination

http://v2p.fr.eu.org
http://www.obry.net

gpg --keyserver keys.gnupg.net --recv-key F949BD3B
J-P. Rosen
2014-12-26 15:48:28 UTC
Permalink
Post by Pascal Obry
Post by Tony
Why? I would expect things to improve with newer versions instead of becoming worse.
Nothing is becoming worse you are just looking at different things.
Maybe the OP is thinking that bigger size => more code => worse code.

Of course, this is a very naive view. Things are MUCH more
complicated... (for one thing: more code may mean faster code, think of
loop unrolling for example).
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
Simon Clubley
2014-12-26 15:55:52 UTC
Permalink
Post by Pascal Obry
Since when "bigger size" means worse?
When you need the resulting executable to fit in fixed size flash memory. :-)

(I'm answering the general question here and not discussing the OP's
current environment.)
Post by Pascal Obry
Have you looked at the actual code size (.text section)?
This is exactly what I was going to ask.

It would be interesting for the OP to run the binutils size command on
both executables and post the results.
Post by Pascal Obry
What is the price of the disk today compared to 10 years ago?
Not all executables run on a desktop PC. If current versions of GNAT
have increased the actual minimum executable size this may be of
interest for embedded environments.

Simon.
--
Simon Clubley, ***@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world
Tony
2014-12-26 20:14:28 UTC
Permalink
Post by Simon Clubley
It would be interesting for the OP to run the binutils size command on
both executables and post the results.
OK, GNAT 3.15p:
C:\Tony\Ada_program\Tests>size hello.exe -A
hello.exe :
section size addr
.text 62428 4198400
.data 2244 4263936
.bss 21124 4268032
.idata 2416 4292608
Total 88212

GNAT 2014:
C:\Tony\Ada_program\Tests>size hello.exe -A
hello.exe :
section size addr
.text 133348 4198400
.data 1092 4333568
.rdata 15500 4337664
.eh_fram 41432 4354048
.bss 13892 4399104
.idata 5112 4415488
.CRT 52 4423680
.tls 32 4427776
Total 210460
Randy Brukardt
2014-12-27 01:48:03 UTC
Permalink
Post by Tony
Post by Simon Clubley
It would be interesting for the OP to run the binutils size command on
both executables and post the results.
C:\Tony\Ada_program\Tests>size hello.exe -A
section size addr
.text 62428 4198400
.data 2244 4263936
.bss 21124 4268032
.idata 2416 4292608
Total 88212
C:\Tony\Ada_program\Tests>size hello.exe -A
section size addr
.text 133348 4198400
.data 1092 4333568
.rdata 15500 4337664
.eh_fram 41432 4354048
.bss 13892 4399104
.idata 5112 4415488
.CRT 52 4423680
.tls 32 4427776
Total 210460
As should be obvious, the tasking runtime for Ada 2005 and Ada 2012 is
substantially more complex than that for Ada 95 alone. Since GNAT doesn't
eliminate the tasking runtime (like Janus/Ada does), the program size is
going to go up for every new Ada version (and probably every new compiler
version, too). Even with Janus/Ada, the runtime tends to go up a bit with
every version (more detailed messages for handling, additional capabilities
for the heap, etc.)

But that's all irrelevant unless you are targetting a very small embedded
system. In which case, you'd be better off with a compiler that was designed
to target very small systems (hint, hint :-). Otherwise, there is so much
memory available, and so much of the newer capabilities that are probably
used in a real system, that there really isn't any point in worrying about
it.

Now, if you have a reference set of programs that double in size, that might
be relevant. (Lots of memory doesn't mean that it is completely free.)
Otherwise, it matters about as much as the runtime performance on the old
Byte Primes benchmark.

Randy.
Pascal Obry
2014-12-27 09:35:36 UTC
Permalink
Post by Simon Clubley
Not all executables run on a desktop PC. If current versions of GNAT
have increased the actual minimum executable size this may be of
interest for embedded environments.
Well in that case looking at a Hello World program which is dragging a
good part of the Ada runtime is even worse :)
--
Pascal Obry / Magny Les Hameaux (78)

The best way to travel is by means of imagination

http://v2p.fr.eu.org
http://www.obry.net

gpg --keyserver keys.gnupg.net --recv-key F949BD3B
Jean François Martinez
2014-12-27 21:17:04 UTC
Permalink
Post by Simon Clubley
Post by Pascal Obry
Since when "bigger size" means worse?
When you need the resulting executable to fit in fixed size flash memory. :-)
We are on x86. Being bigger on does not necessarily mean it will be biger on another architecture particularly because we are speaking of executable size ie with inclusion of newer libraries and runtime. For embedded you would use tailored ones.

Jean-François Martinez
Loading...