Sunday, January 12, 2020

Start of LFS section 5 through 5.4

This chapter is about building a temporary system to bootstrap the system with the required basic tools and utilities needed to build the actual target system.

Section 5.1 Introduction

Contains a short introduction about creating the temporary system with needed tools installed under $LFS/tools/.  This tool chain will be used to build the final version of the basic LFS system.  There is no steps or instructions needed for this section.

Section 5.2 Toolchain Technical Notes

This section contains useful information about the temporary toolchain that is about to be built.  The technical details has some notes about cross-compiling and gives a brief overview of the upcoming steps.  There is no steps or instructions needed for this section, feel free to read the LFS book for additional info.

Section 5.3 General Compilation Instructions

This section contains generic information about build steps, such as:
  • Ensure $LFS is set
  • Sources directory is available under the $LFS location and is NOT under the tools directory
  • When building a package:
    • Change to the sources directory.
    • Untar the given package.
    • Change to the unpacked directory.
    • Use the book instructions for compiling and installing the given package.
    • When done change back to the sources directory, and remove the unpacked package, unless otherwise instructed.
I may need to adapt these steps for my layout for several reasons.  I am not untaring pre-built packages, but will be building in a checked out repository.  Sometimes build steps or settings may need to be slightly modified when building from a repository directory vs a 'built' release version tarball that in some cases may have been slightly modified durring packaging to allow builds.  In addition I will be using ZFS snapshots, cleans, rollbacks as necissary to clean up my builds.

Section 5.4 Binutils-2.33 Pass 1

Package Information:

The binutils package contains a linker, an assembler, and other tools for handling object files.
Approximate build time: 1 SBU
Required disk space: 659 MB

Build Prep and Timing

Recommends wrapping all the commands in a time { ... } to get a feel for how long '1 SBU' takes. For details on what all the options in the following commands mean, I recommend just reading the LFS book. My prep output is as follows:

 gentoo@livecd ~ $ echo $LFS  
 /rootPool/root_fs  
 gentoo@livecd ~ $ env  
 TERM=xterm  
 MAKEFLAGS=-j44  
 LC_ALL=POSIX  
 LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.cfg=00;32:*.conf=00;32:*.diff=00;32:*.doc=00;32:*.ini=00;32:*.log=00;32:*.patch=00;32:*.pdf=00;32:*.ps=00;32:*.tex=00;32:*.txt=00;32:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:  
 LFS=/rootPool/root_fs  
 PATH=/tools/bin:/sbin:/bin:/usr/bin  
 PWD=/home/gentoo  
 LFS_TGT=x86_64-lfs-linux-gnu  
 PS1=\[\033]0;\u@\h:\w\007\]\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\]   
 SHLVL=1  
 HOME=/home/gentoo  
 _=/bin/env  
 gentoo@livecd ~ $ cd $LFS/sources/binutils  
 gentoo@livecd /rootPool/root_fs/sources/binutils $ cd binutils-gdb/  
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb $ git status  
 HEAD detached at binutils-2_33_1  
 nothing to commit, working directory clean  
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb $ /sbin/zfs snapshot rootPool/root_fs/sources/binutils@lfs_prep_section_5.4_pass1  
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb $   
   

Configure/Build/Install

So I could easily time and recreate the commands need to build this pass, I created the following script:
 gentoo@livecd /rootPool/root_fs/sources/binutils $ cat build_binutils_temp_pass1.sh   
 #!/bin/bash  
 set -x  
   
 # Change into the repository  
 cd binutils-gdb  
   
 # Create a build location, and change to it.  
 mkdir -v build  
 cd build  
   
 # Run the configuration  
 ../configure --prefix=/tools            \  
              --with-sysroot=$LFS        \  
              --with-lib-path=/tools/lib \  
              --target=$LFS_TGT          \  
              --disable-nls              \  
              --disable-werror  
   
 # Build bin-utils  
 make  
   
 # create reequired install locations for x64 as needed  
 case $(uname -m) in  
  x86_64) mkdir -v /tools/lib && ln -sv lib /tools/lib64 ;;  
 esac  
   
 # Install the bin-utils  
 make install  
 gentoo@livecd /rootPool/root_fs/sources/binutils $   
   

When running the script I received the following error(s):
 mkdir: cannot create directory '/tools/lib': No such file or directory  
 + make install  
 make[1]: Entering directory '/rootPool/root_fs/sources/binutils/binutils-gdb/build'  
 /bin/sh ../mkinstalldirs /tools /tools  
 make[1]: Nothing to be done for 'install-target'.  
 mkdir -p -- /tools /tools  
 mkdir: cannot create directory '/tools': Permission denied  
 mkdir: cannot create directory '/tools': Permission denied  
 make[1]: *** [Makefile:2505: installdirs] Error 1  
 make[1]: Leaving directory '/rootPool/root_fs/sources/binutils/binutils-gdb/build'  
 make: *** [Makefile:2258: install] Error 2  
   

What I forgot about is that in section 4,
 livecd gentoo # ln -sv $LFS/tools /   
  '/tools' -> '/rootPool/root_fs//tools'   
on the host system, that this would NOT be persistent across reboot, so I need to add this item to the persistent startup script to set the symbolic link back up. After rebooting I now have a /tools link as can be seen here:
 gentoo@livecd ~ $ ls -l /  
 total 1  
 drwxr-xr-x   2 root   root  1660 Jul  3  2016 bin  
 drwxr-xr-x   2 root   root    28 Jul  3  2016 boot  
 drwxr-xr-x  18 root   root  5700 Jan 13 01:13 dev  
 drwxr-xr-x 127 root   root   420 Jan 13 01:19 etc  
 drwxr-xr-x   4 gentoo users    5 May 28  2019 gentooScratch  
 drwxr-xr-x   4 root   root    60 Jan 13 01:13 home  
 lrwxrwxrwx   1 root   root     5 Jun 23  2016 lib -> lib64  
 drwxr-xr-x   2 root   root  1070 Jun 23  2016 lib32  
 drwxr-xr-x  18 root   root    60 Jan 13 01:13 lib64  
 drwxr-xr-x   2 root   root    28 Oct 28  2015 media  
 drwxr-xr-x   6 root   root   120 Jan 13 01:12 mnt  
 drwxr-xr-x   2 root   root    40 Jan 13 01:12 newroot  
 drwxr-xr-x   5 root   root    64 Oct 28  2015 opt  
 dr-xr-xr-x 626 root   root     0 Jan 13 01:12 proc  
 drwx------   3 root   root    60 Jan 13 01:13 root  
 drwxr-xr-x   3 root   root     3 Jun  3  2019 rootPool  
 drwxr-xr-x  19 root   root   660 Jan 13 01:47 run  
 drwxr-xr-x   2 root   root  5023 Jul  3  2016 sbin  
 dr-xr-xr-x  13 root   root     0 Jan 13 01:12 sys  
 drwxrwxrwt   6 root   root   220 Jan 13 01:47 tmp  
 lrwxrwxrwx   1 root   root    23 Jan 13 01:19 tools -> /rootPool/root_fs/tools  
 drwxr-xr-x  21 root   root   180 Jan 13 01:17 usr  
 drwxr-xr-x  13 root   root   100 Jan 13 01:13 var  
   

Now I can rollback to the rootPool/root_fs/sources/binutils@lfs_prep_section_5.4_pass1 snapshot I made.  This time I will redploy my script and make a new snapshot with my build script, and run again.
 gentoo@livecd ~ $ sudo zfs rollback -r rootPool/root_fs/sources/binutils@lfs_prep_section_5.4_pass1   
 gentoo@livecd ~ $ mv build_binutils_temp_pass1.sh /rootPool/root_fs/sources/binutils   
 gentoo@livecd ~ $ /sbin/zfs snapshot rootPool/root_fs/sources/binutils@lfs_prep_section_5.4_pass1_scripted  
 gentoo@livecd ~ $ /sbin/zfs snapshot rootPool/root_fs/tools@lfs_prep_section_5.4_pass1_scripted  
 gentoo@livecd ~ $ mv lfs.bash_profile .bash_profile  
 gentoo@livecd ~ $ mv lfs.bashrc .bashrc                                     
 gentoo@livecd ~ $ source .bash_profile                                      
 gentoo@livecd ~ $ env                                              
 TERM=xterm                                                    
 MAKEFLAGS=-j44                                                  
 LC_ALL=POSIX                                                   
 LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.cfg=00;32:*.conf=00;32:*.diff=00;32:*.doc=00;32:*.ini=00;32:*.log=00;32:*.patch=00;32:*.pdf=00;32:*.ps=00;32:*.tex=00;32:*.txt=00;32:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:  
 LFS=/rootPool/root_fs  
 PATH=/tools/bin:/sbin:/bin:/usr/bin  
 PWD=/home/gentoo  
 LFS_TGT=x86_64-lfs-linux-gnu  
 PS1=\[\033]0;\u@\h:\w\007\]\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\]   
 SHLVL=1  
 HOME=/home/gentoo  
 _=/bin/env  
 gentoo@livecd ~ $ ls -ld /tools   
 lrwxrwxrwx 1 root root 23 Jan 13 01:19 /tools -> /rootPool/root_fs/tools  
 gentoo@livecd ~ $ cd $LFS/sources/binutils  
 gentoo@livecd /rootPool/root_fs/sources/binutils $ ls  
 binutils-gdb build_binutils_temp_pass1.sh  
 gentoo@livecd /rootPool/root_fs/sources/binutils $ time ./build_binutils_temp_pass1.sh...
[WHOLE BUNCH OF CONFIGURE, MAKE, COMPILER OUTPUT REMOVED FOR BREVITY]
...     
 make[3]: Leaving directory '/rootPool/root_fs/sources/binutils/binutils-gdb/build/gdb'  
 make[2]: Leaving directory '/rootPool/root_fs/sources/binutils/binutils-gdb/build/gdb'  
 make[1]: Leaving directory '/rootPool/root_fs/sources/binutils/binutils-gdb/build'  
   
 real  0m58.416s  
 user  10m43.418s  
 sys   1m8.464s  
 gentoo@livecd /rootPool/root_fs/sources/binutils $
   

SBU Timings

Because I am using ZFS snapshots, I can perform the rollbacks as many times as I want to re-perform the build steps.  This will actually allow me to benchmark the approximate amount of time per SBU with different thread counts.  Also if there are build errors I can effectively reset, determine what went wrong, fix it, and re-perform the build steps, with a clean state as if I had not attempted the build at all:
 gentoo@livecd ~ $ sudo zfs rollback rootPool/root_fs/sources/binutils@lfs_prep_section_5.4_pass1_scripted  
 gentoo@livecd ~ $ sudo zfs rollback rootPool/root_fs/tools@lfs_prep_section_5.4_pass1_scripted  
 gentoo@livecd ~ $ export MAKEFLAGS='-j1'  
 gentoo@livecd ~ $ cd /rootPool/root_fs/sources/binutils/  
 gentoo@livecd /rootPool/root_fs/sources/binutils $ time ./build_binutils_temp_pass1.sh
+ cd binutils-gdb
+ mkdir -v build
mkdir: created directory 'build'
+ cd build
+ ../configure --prefix=/tools --with-sysroot=/rootPool/root_fs --with-lib-path=/tools/lib --target=x86_64-lfs-linux-gnu --disable-nls --disable-werror
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking target system type... x86_64-lfs-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c...
[WHOLE BUNCH OF CONFIGURE, MAKE, COMPILER OUTPUT REMOVED FOR BREVITY]
...make[1]: Nothing to be done for 'install-target'.
make[1]: Leaving directory '/rootPool/root_fs/sources/binutils/binutils-gdb/build'
real    6m52.944s
user    5m50.666s
sys     0m35.333s        

A quick explination about the time values.  The 'real' time is the wall clock time that has passed between entering the command and the command is complete.  The user time is the accounting time of how much cpu time was executing userland code.  The sys time is the accounting time of how much cpu time was executing kernel/syscall functions, including IO waits.  As an simplified example, in the first scenerio where we had the real/user/sys times of 0:58/10:43/1:08, with code running on all 32 threads, each thread on average spent about 2 seconds waiting on IO or waiting on the OS to perform a task for its behalf.  Also each thread spent on average about 20 seconds actually compiling.  Because of the the multiple cores/threads available in the system it was able to schedule all the work in parallel in about a minute.  In the second example, since we only ran with 1 thread on 1 core, nothing was done in parallel therefore the total/real time had to wait for that one thread to perform all the user and system tasks in order, therefore taking as much or more wall clock as the actual work...

The next question you may ask is, why did the total user and sys times take less with just 1 thread.  There are several things that could cause this difference in time.
  1. Thread-Resource Contention.

    This is where one thread can not execute because another thread is currently exclusively using a resource it needs.  This resource could be an execution unit on the CPU itself, a memory operation to main-memory, a file operation on the disk, or some-other resource both compiling threads need access to.  Depending on the type of resource the thread is waiting on will determine which accounting time is incremented while the thread is waiting.
  2. Cached Resources.

    Since the '1 thread' version was run after the '44 thread version', some items may have already been loaded into memory, so the make process did not actually have to go back to disk durring the 2nd compile.  This can include both the tool chains (make, shell, compiler, assembler, linker, libraries) which have to load from the slow gentoo usb flash OR which portions of the source code are already in the ZFS ARC, based on usage and available memory.  Typically when benchmarking one will throw out the 'first' run, because that run will warm up (assuming enough memory to hold the data set in memory) the tools and data into main memory and/or other system caches.
  3. Compile Dependencies.

    Not all of the items can be run in parallel.  Certain steps require other portions of the build to have already been completed.  With multiple threads, there can be time spent waiting for a previous step to have completed, before running the current step on the current thread.  For the single thread version, all steps are done sequentially so there is no time spent waiting for a previous step, since it won't be queued for work untill the prior dependencies have all completed.
  4. Other Computer Tasks.

    Other programs running on the computer during compile.  This includes both background, scheduled, and user UI tasks that may have been going on while I was waiting for the compile to complete.
What I have decided to do, to get a good feel for my system's SBU value, is to re-run this build with different values of thread settings to get a good benchmark of values.  Using the commands in the last example, but with different numeric values of '-j#' I came up with the following data:


Threads 1 2 4 8 12 16 17 24 32 32* 33 40 44 64
Real 6:52.127 3:39.783 1:59.355 1:24.866 1:04.054 1:00.332 0:59.636 0:58.843 0:58.156 0:57.727 0:58.141 0:58.279 0:58.658 0:58.945
User  5:49.268  5:54.943  6:03.927  6:28.973  6:49.164  7:23.114  7:37.813  9:26.583  10:48:781  10:45.696  10:55.746  10:56.867  11:03.175  11:01.951
Sys 0:35.268 0:35.745 0:37.309 0:41.800 0:44.180 0:48.328 0:50.493 1:00.726 1:08.731 1:06.232 1:08.551 1:08.171 1:10.394 1:08.338
The *note on the 2nd run of 32 threads was redirecting output to a file instead of the text console.

It looks like binutils build had diminishing returns after 16 threads, and seems to compile fastest at 32 threads.  Using more threads (such as my current default value of 44) does not significantly slow it back down past 32, so I will probably leave that value set.  Note that we now have a base SBU value of about 1 minute per SBU.  When compiling with multiple threads there will be more variance per SBU based on the package layout, design, make configuration, and internal dependencies.  Because of this some packages may do significantly better or worse then 1 minute per SBU.

Final Cleanup.


Once a package has successfully built we are left with some clean up steps.  The LFS book talks about deleting the unpacked package.  Instead we are going to do a different set of steps.  We will snapshot the build and install, we will perform a clean, we will perform a snapshot, and then if needed manually clean any remaining changes and perform a final snapshot as follows:
 gentoo@livecd /rootPool/root_fs/sources/binutils $ zfs snapshot rootPool/root_fs/sources/binutils@lfs_built_section_5.4_pass1  
 gentoo@livecd /rootPool/root_fs/sources/binutils $ zfs snapshot rootPool/root_fs/tools@lfs_install_section_5.4_pass1  
 gentoo@livecd /rootPool/root_fs/sources/binutils $ cd binutils-gdb/build/  
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb/build $ make clean && make distclean  
 rm -f *.a TEMP errs core *.o *~ \#* TAGS *.E *.log  
 make[1]: Entering directory '/rootPool/root_fs/sources/binutils/binutils-gdb/build'  
 make[1]: Nothing to be done for 'clean-target'.  
 Doing clean in binutils  
 [...ADDITIONAL MAKE OUTPUT FOR CLEAN OMITTED FOR BREVITY...]  
 find . -name config.cache -exec rm -f {} \; \; 2>/dev/null  
 make: [Makefile:2104: local-distclean] Error 1 (ignored)  
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb/build $ cd ..  
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb $ rm -rf build  
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb $ zfs snapshot rootPool/root_fs/sources/binutils@lfs_cleaned_section_5.4_pass1  
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb $ git status  
 HEAD detached at binutils-2_33_1  
 nothing to commit, working directory clean
 gentoo@livecd /rootPool/root_fs/sources/binutils/binutils-gdb $ cd ../..
 gentoo@livecd /rootPool/root_fs/sources $                 
In this case, git did not show any modified or untracked files, so the source repository is clean, and this section is now complete.

Next time I will start in on section 5.5 to cross-compile gcc for the temporary system.

No comments:

Post a Comment