File size and smartlinking

From Free Pascal wiki
Jump to navigationJump to search

Deutsch (de) English (en) français (fr) 日本語 (ja) português (pt) 中文(中国大陆)‎ (zh_CN)

This article is a work in progress about executable size and smartlinking on Lazarus. Feel free to contribute.

Introduction

In Free Pascal, "smartlinking" is removing unused code and variables from the final executable. This is done during the linking stage, when the executable is written using the object files created by the compiler earlier.

Case study 1 in Windows

This study was conducted on the 8th of February 2006 because a Lazarus fully compiled with Smartlinking was Released (version 0.9.12). It intends to establish the relationship between the varying results below with different Lazarus and Free Pascal versions as well as with Smartlinking and without.


The Variables being studied are:

  • Executable size after strip
  • Executable size after strip and UPX
  • Linking time


Compile time isn´t considered here because it´s too similar on all configurations and much less significant than the link time.


Executable size without strip isn´t included. Notice that strip was used always from command line with the command:

strip --strip-all magnifier.exe


The program being compiled is the Virtual Magnifying Glass. The source and binaries for this program are freely available for download on: http://magnifier.sourceforge.net


About the linking time please note that the utilized computer is 3.2GHz Pentium 4 with Intel motherboard and dual core processor and 512MB of RAM.


Results


The utilized OS is Windows XP and the 0.9.13 versions are from the same date when 0.9.12 was release. The comparison took place using the following software configurations:

  • Lazarus 0.9.12 available here. Free Pascal 2.0.2 that comes with the installer. LCL and RTL are smartlinked. Refered from now on as simply 0.9.12.
  • Lazarus 0.9.13 downloaded from Subversion from the same date. Free Pascal 2.0.2 installed separately. The LCL is not smartlinked. Refered from now on as simply 0.9.13 + 2.0.2.
  • Lazarus 0.9.13 snapshot. Free Pascal 2.1 that comes with the installer. The LCL is not smartlinked. Refered from now on as simply 0.9.13 + 2.1.
  • Lazarus 0.9.13 snapshot. Free Pascal 2.1 that comes with the installer. The LCL is smartlinked. Refered from now on as simply 0.9.13 + 2.1 + SL.
0.9.12 0.9.13 + 2.0.2 0.9.13 + 2.1 + SL 0.9.13 + 2.1
File Size after strip (in bytes) 1,108,480 1,587,712 1,425,408 1,649,152
File Size after UPX (in bytes) 318,976 438,272 388,608 454,144
Linking time 15 seconds 5 seconds 45 seconds 10 seconds

OuptutFileSizesComparisonChart.png

Conclusion


The 0.9.13 snapshot from the 8th of February 2006 features a unstable compiler from the 2.1 branch, which can cause the bigger executables and slower linking time as compared to the other versions.


The 0.9.12 version has the best file size of all, both with UPX and without, showing that Smartlinking really can diminish the file size in Windows. This, however, does not come without a cost, and the cost is linking time, which is about 3 times higher then without smartlinking.


The 0.9.12 version already comes fully configured for Smartlinking on Windows and no extra configuration is needed. This was not the case on previous releases.

Remove unused functions in a class

Q: If a virtual method of a class is not used at all in the programm will the compiler remove it from the executable ?

A: If you use FPC 2.3.1 with whole-program optimization and the compiler can prove that it is never callable: yes. See Whole Program Optimization for more information. In case this is in relation to the thread on the Lazarus list about the big executables: note that it has only a limited effect on Lazarus programs, because almost all linked LCL code can potentially be executed (due to the way the LCL is constructed). In fact, I think most savings there come from making a number of virtual method calls non-virtual, rather than from throwing away unreachable code.

The internal linker can also do it (only throwing away virtual method calls, not turning virtual method calls into static ones), but only on Windows platforms. It is however not currently enabled in the compiler, because the changes break the external linker. It should therefore be turned into a command line option (along with a check that produces an error if you try to link a unit compiled with the option using the external linker), but that hasn't been done yet.

Q: How can the compiler determine that a virtual method is unused at all,

A: If you have a class hierarchy TBase->TDerived1->TDerived2 with a virtual method called "vmethod", and nowhere in the program there is a call to vmethod, then it is unused. Or if it is only called using TDerived2 instances, then if the linker does not find any direct references to TDerived1.vmethod or TBase.vmethod (e.g., via "inherited" calls from TDerived2 methods), it knows that the VMT entries for "vmethod" in TDerived1 and TBase can be set to nil.

Bytes Used

Here's a layout by pascal units in bytes used for code. The size is based on Dwarf2 information generated. Doesn't include resources size used by a unit.

The project is a single form application (no additional controls used). Lazarus used is a Trunk version of 23 Jan 2020.

No optimization was used during compilation.

Size Lib Package Category File name
238704 lcl controls.pp
144064 lcl graphics.pp
111280 lcl ws win32/win32int.pp
106880 lcl forms.pp
98000 lcl system.pp
94432 lcl intfgraphics.pas
90352 lcl comctrls.pp
90224 rtl classes.pp
59552 lcl stdctrls.pp
51888 lcl ws interfacebase.pp
50336 rtl ../win/sysutils.pp
37728 lcl imglist.pp
35456 rtl rtl-objpas/src/inc/variants.pp
33232 lcl lazutils lazutf8.pas
31456 lcl extctrls.pp
30912 fcl image fcl-image/src/fpreadtiff.pas
30816 lcl ws win32/win32wscomctrls.pp
30800 lcl ws win32/win32wsmenus.pp
28832 lcl menus.pp
25984 lcl maskedit.pp
24480 rtl rtl-objpas/src/win/varutils.pp
24048 lcl dialogs.pp
23632 fcl json fcl-json/src/fpjson.pp
23456 lcl ws win32/win32wsstdctrls.pp
23408 lcl lclintf.pas
18448 lcl lresources.pp
17904 lcl lazutils textstrings.pas
16736 fcl image fcl-image/src/fpcanvas.pp
16544 lcl lazutils graphtype.pp
13408 lcl themes.pas
13168 lcl ws win32/win32proc.pp
13136 fcl image fcl-image/src/pixtools.pp
13088 lcl lazutils lazloggerbase.pas
12368 lcl lazutils laz_avl_tree.pp
11872 fcl image fcl-image/src/fpimage.pp
11776 lcl base actnlist.pas
11488 lcl base buttons.pp
10576 rtl debug ../inc/heaptrc.pp
10544 lcl ws win32/win32wsbuttons.pp
10464 rtl ../objpas/typinfo.pp
9744 fcl image fcl-image/src/fpreadpng.pp
9696 lcl base graphmath.pp
9536 lcl lazutils lazlogger.pas
9424 lcl lazutils lazfileutils.pas
9296 lcl base buttonpanel.pas
9248 fcl image fcl-image/src/fpwritetiff.pas
8864 lcl base clipbrd.pp
8768 lcl ws win32/win32extra.pas
8768 fcl jpeg pasjpeg/src/jquant2.pas
8720 fcl jpeg pasjpeg/src/jdmarker.pas
8160 fcl image fcl-image/src/fpwritepng.pp
8016 fcl image fcl-image/src/fpwritebmp.pp
7792 fcl zlib paszlib/src/trees.pas
7648 fcl zlib paszlib/src/zdeflate.pas
7536 fcl image fcl-image/src/ellipses.pp
7472 lcl ws win32/win32wsforms.pp
7456 fcl image fcl-image/src/fpreadbmp.pp
7328 lcl ws win32/win32themes.pas
6880 fcl jpeg pasjpeg/src/jdcoefct.pas
6864 lcl base lclproc.pas
6624 lcl lazutils lazutf16.pas
6400 lcl ws win32/win32wscontrols.pp
6240 fcl zlib paszlib/src/infblock.pas
5920 lcl base lclrescache.pas
5792 fcl image fcl-image/src/fpreadjpeg.pas
5728 fcl image fcl-image/src/fppixlcanv.pp
5680 fcl ws win32/win32wsspin.pp
5648 lcl lazutils maps.pp
5632 lcl ws win32/win32wsimglist.pp
5568 fcl jpeg pasjpeg/src/jchuff.pas
5520 fcl jpeg pasjpeg/src/jmemmgr.pas
5392 fcl jpeg pasjpeg/src/jquant1.pas
5264 fcl image fcl-image/src/fpreadgif.pas
5232 fcl jpeg pasjpeg/src/jdphuff.pas
5152 lcl base imagelistcache.pas
5104 lcl base widgetset/wsstdctrls.pp
5008 fcl json fcl-json/src/jsonscanner.pp
4992 lcl base widgetset/wslclclasses.pp
4880 fcl jpeg pasjpeg/src/jcphuff.pas
4848 fcl utils fcl-base/src/contnrs.pp
4816 fcl image fcl-image/src/fptiffcmn.pas
4768 rtl debug ../inc/lnfodwrf.pp
4640 fcl jpeg pasjpeg/src/jcmaster.pas
4592 fcl jpeg pasjpeg/src/jdhuff.pas
4512 fcl jpeg pasjpeg/src/jcparam.pas
4256 fcl jpeg pasjpeg/src/jcsample.pas
4208 lcl base widgetset/wscomctrls.pp
4160 fcl zlib paszlib/src/infcodes.pas
3936 fcl zlib paszlib/src/inftrees.pas
3616 fcl jpeg pasjpeg/src/jcmarker.pas
3584 fcl zlib paszlib/src/zstream.pp
3584 fcl jpeg pasjpeg/src/jidctint.pas
3488 fcl image fcl-image/src/fpwritepnm.pp
3472 fcl image fcl-image/src/fpreadpnm.pp
3360 fcl jpeg pasjpeg/src/jdmerge.pas
3312 lcl base icnstypes.pas
3248 fcl jpeg pasjpeg/src/jccoefct.pas
3216 fcl pasjpeg/src/jdsample.pas
3168 fcl pasjpeg/src/jdmainct.pas
3152 lcl widgetset/wsimglist.pp
3120 lcl spin.pp
3120 fcl pasjpeg/src/jdmaster.pas
3104 rtl winapi winunits-base/src/uxtheme.pp
2992 lcl widgetset/wscontrols.pp
2944 fcl fcl-json/src/jsonparser.pp
2896 fcl pasjpeg/src/jccolor.pas
2848 fcl paszlib/src/zinflate.pas
2832 fcl pasjpeg/src/jdcolor.pas
2816 fcl pasjpeg/src/jcdctmgr.pas
2752 lcl lazutils lazmethodlist.pas
2736 fcl pasjpeg/src/jidctred.pas
2704 rtl ../inc/exeinfo.pp
2688 fcl pasjpeg/src/jidctfst.pas
2576 fcl pasjpeg/src/jidctflt.pas
2496 rtl ../objpas/fgl.pp
2464 fcl pasjpeg/src/jdinput.pas
2448 lcl ws win32/win32wsfactory.pas
2352 fcl image fcl-image/src/fpwritejpeg.pas
2320 fcl pasjpeg/src/jcprepct.pas
2208 lcl lazutils lclclasses.pp
2032 fcl pasjpeg/src/jerror.pas
2016 rtl winunits-base/src/multimon.pp
2016 fcl pasjpeg/src/jfdctint.pas
1952 rtl windows.pp
1888 fcl pasjpeg/src/jdapimin.pas
1872 fcl image fcl-image/src/clipping.pp
1824 fcl paszlib/src/inffast.pas
1808 lcl extendedstrings.pas
1712 lcl customtimer.pas
1648 lcl helpintfs.pas
1584 fcl pasjpeg/src/jfdctfst.pas
1584 fcl pasjpeg/src/jfdctflt.pas
1584 rtl ../objpas/math.pp
1472 fcl pasjpeg/src/jdpostct.pas
1360 fcl pasjpeg/src/jdapistd.pas
1280 fcl fcl-base/src/custapp.pp
1200 lcl lazfilecache.pas
1152 lcl widgetset/wsmenus.pp
1152 lcl lazutils lazclasses.pas
1120 fcl pasjpeg/src/jddctmgr.pas
1056 lcl widgetset/wsforms.pp
1040 lcl integerlist.pas
1024 fcl pasjpeg/src/jcapimin.pas
992 lcl lcltype.pp
848 lcl lazstringutils.pas
832 fcl fcl-image/src/fpimgcanv.pp
768 lcl widgetset/wsproc.pp
688 rtl ../objpas/types.pp
672 lcl win32/win32wsdialogs.pp
672 lcl lazutf8classes.pas
656 fcl pasjpeg/src/jcmainct.pas
656 rtl ../inc/fpintres.pp
640 lcl laztracer.pas
624 fcl pasjpeg/src/jdatasrc.pas
560 fcl fcl-image/src/fpimgcmn.pp
528 fcl paszlib/src/infutil.pas
528 fcl fcl-base/src/syncobjs.pp
512 lcl lclmessageglue.pas
496 fcl pasjpeg/src/jutils.pas
496 fcl pasjpeg/src/jdatadst.pas
480 fcl pasjpeg/src/jcapistd.pas
464 rtl winunits-base/src/commctrl.pp
432 lcl widgetset/wsextctrls.pp
432 fcl paszlib/src/zbase.pas
384 fcl pasjpeg/src/jmemnobs.pas
368 fcl pasjpeg/src/jcomapi.pas
336 rtl ../objpas/objpas.pp
288 lcl widgetset/wsdialogs.pp
288 fcl fcl-xml/src/htmldefs.pp
256 fcl pasjpeg/src/jinclude.pas
256 fcl pasjpeg/src/jcinit.pas
256 lcl lcltaskdialog.pas
256 lcl laz2_xmlread.pas
224 lcl widgetset/wsspin.pp
208 lcl widgetset/wsbuttons.pp
208 fcl paszlib/src/adler.pas
192 rtl ../objpas/unicodedata.pas
144 lcl avglvltree.pas
128 lcl widgetset/wsreferences.pp
112 lcl stringhashlist.pas
112 main project1.lpr
96 rtl ../win/windirs.pp
96 rtl ../win/dos.pp
80 lcl lclversion.pas
80 lcl lclplatformdef.pas
80 lcl forms/calcform.pas
80 lcl lazutils fileutil.pas
64 lcl ws win32/interfaces.pp
64 lcl lazutilities.pas
64 lcl laz2_dom.pas
64 rtl ../inc/strings.pp
48 lcl lconvencoding.pas
48 lcl lazsysutils.pas
48 lcl laz2_xmlutils.pas
48 lcl fpcadds.pas
48 fcl fcl-base/src/rttiutils.pp
32 fcl fcl-base/src/gettext.pp

Code size by lib

lib code percentage
rtl 152528 6.92%
lcl 1679408 76.19%
fcl 372176 16.88%
main 122 0.01%
Total 2204234 100%

See Also