Ah! I finally have a progress bar that doesn't stall the build!
author"Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun May 20 13:48:26 2007 +0000 (2007-05-20)
changeset 112ea15433daba0
parent 111 2e16b9fc302d
child 113 0a1e72093a51
Ah! I finally have a progress bar that doesn't stall the build!
- pipe size in Linux is only 8*512=4096 bytes
- pipe size is not setable
- when the feeding process spits out data faster than the eating
process can read it, then the feeding process stalls after 4KiB
of data sent to the pipe
- for us, the progress bar would spawn a sub-shell every line,
and the sub-shell would in turn spawn a 'date' command.
Which was sloooww as hell, and would cause some kind of a
starvation: the pipe was full most of the time, and the
feeding process was stalled all this time.

Now, we use internal variables and a little hack based onan offset
to determine the elapsed time. Much faster this way, but still
CPU-intensive.
config/global.in
scripts/crosstool.sh
scripts/functions
     1.1 --- a/config/global.in	Sun May 20 09:28:16 2007 +0000
     1.2 +++ b/config/global.in	Sun May 20 13:48:26 2007 +0000
     1.3 @@ -255,13 +255,15 @@
     1.4      default n
     1.5      depends on ! LOG_ALL
     1.6      help
     1.7 -      This option will print a "rotating bar" (/-\|) below the last log line
     1.8 -      to show work is not stalled.
     1.9 +      If you say 'y' here, you'll be able to see the elapsed time.
    1.10        
    1.11 -      Available when not in DEBUG log level.
    1.12 -      
    1.13 -      WARNING! Very CPU intensive! If you have spare CPU, then you can use it,
    1.14 -      otherwise, refrain from using it.
    1.15 +      As a bonus, you'll also get a rotating bar (/-\|) showing you
    1.16 +      that the build is not stalled (the bar rotates 1/4 every 10 lines
    1.17 +      of components build log).
    1.18 +
    1.19 +      Note that the elapsed time can stall for a little while if a
    1.20 +      component has long commands, as the elapsed time is only updated
    1.21 +      each line.
    1.22  
    1.23  config LOG_TO_FILE
    1.24      bool
     2.1 --- a/scripts/crosstool.sh	Sun May 20 09:28:16 2007 +0000
     2.2 +++ b/scripts/crosstool.sh	Sun May 20 13:48:26 2007 +0000
     2.3 @@ -27,8 +27,12 @@
     2.4  CT_STAR_DATE=`CT_DoDate +%s%N`
     2.5  CT_STAR_DATE_HUMAN=`CT_DoDate +%Y%m%d.%H%M%S`
     2.6  
     2.7 -# Log to a temporary file until we have built our environment
     2.8 -CT_ACTUAL_LOG_FILE="${CT_TOP_DIR}/$$.log"
     2.9 +# Log policy:
    2.10 +#  - what goes to the log file goes to fd #1 (stdout)
    2.11 +#  - what goes to the screen goes to fd #6
    2.12 +tmp_log_file="${CT_TOP_DIR}/$$.log"
    2.13 +exec 6>&1
    2.14 +exec >>"${tmp_log_file}"
    2.15  
    2.16  # Are we configured? We'll need that later...
    2.17  CT_TestOrAbort "Configuration file not found. Please create one." -f "${CT_TOP_DIR}/.config"
    2.18 @@ -182,22 +186,22 @@
    2.19  # It's quite understandable that the log file will be installed in the install
    2.20  # directory, so we must first ensure it exists and is writeable (above) before
    2.21  # we can log there
    2.22 +exec >/dev/null
    2.23  case "${CT_LOG_TO_FILE},${CT_LOG_FILE}" in
    2.24 -    ,*)   rm -f "${CT_ACTUAL_LOG_FILE}"
    2.25 -          CT_ACTUAL_LOG_FILE=/dev/null
    2.26 +    ,*)   rm -f "${tmp_log_file}"
    2.27            ;;
    2.28      y,/*) mkdir -p "`dirname \"${CT_LOG_FILE}\"`"
    2.29 -          mv "${CT_ACTUAL_LOG_FILE}" "${CT_LOG_FILE}"
    2.30 -          CT_ACTUAL_LOG_FILE="${CT_LOG_FILE}"
    2.31 +          mv "${tmp_log_file}" "${CT_LOG_FILE}"
    2.32 +          exec >>"${CT_LOG_FILE}"
    2.33            ;;
    2.34      y,*)  mkdir -p "`pwd`/`dirname \"${CT_LOG_FILE}\"`"
    2.35 -          mv "${CT_ACTUAL_LOG_FILE}" "`pwd`/${CT_LOG_FILE}"
    2.36 -          CT_ACTUAL_LOG_FILE="`pwd`/${CT_LOG_FILE}"
    2.37 +          mv "${tmp_log_file}" "`pwd`/${CT_LOG_FILE}"
    2.38 +          exec >>"${CT_LOG_FILE}"
    2.39            ;;
    2.40  esac
    2.41  
    2.42  # Determine build system if not set by the user
    2.43 -CT_Test "You did not specify the build system. Guessing." -z "${CT_BUILD}"
    2.44 +CT_Test "You did not specify the build system. That's OK, I can guess..." -z "${CT_BUILD}"
    2.45  CT_BUILD="`${CT_TOP_DIR}/tools/config.sub \"${CT_BUILD:-\`${CT_TOP_DIR}/tools/config.guess\`}\"`"
    2.46  
    2.47  # Arrange paths depending on wether we use sys-root or not.
     3.1 --- a/scripts/functions	Sun May 20 09:28:16 2007 +0000
     3.2 +++ b/scripts/functions	Sun May 20 13:48:26 2007 +0000
     3.3 @@ -12,7 +12,7 @@
     3.4      for((depth=2; ${BASH_LINENO[$((${depth}-1))]}>0; depth++)); do
     3.5          CT_DoLog ERROR "      called from \"${BASH_SOURCE[${depth}]}\" at line # ${BASH_LINENO[${depth}-1]} in function \"${FUNCNAME[${depth}]}\""
     3.6      done
     3.7 -    CT_DoLog ERROR "Look at \"${CT_ACTUAL_LOG_FILE}\" for more info on this error."
     3.8 +    [ "${CT_LOG_TO_FILE}" = "y" ] && CT_DoLog ERROR "Look at \"${CT_LOG_FILE}\" for more info on this error."
     3.9      CT_STEP_COUNT=1
    3.10      CT_DoEnd ERROR
    3.11      exit $ret
    3.12 @@ -54,30 +54,31 @@
    3.13          cat -
    3.14      else
    3.15          echo "${1}"
    3.16 -    fi |( IFS="\n" # We want the full lines, even leading spaces
    3.17 +    fi |( offset=$((`CT_DoDate +%s`+(CT_STAR_DATE/(1000*1000*1000))))
    3.18 +          IFS="\n" # We want the full lines, even leading spaces
    3.19            CT_PROG_BAR_CPT=0
    3.20            indent=$((2*CT_STEP_COUNT))
    3.21            while read line; do
    3.22                case "${CT_LOG_SEE_TOOLS_WARN},${line}" in
    3.23                  y,*"warning:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
    3.24 +                y,*"WARNING:"*)         cur_L=WARN; cur_l=${CT_LOG_LEVEL_WARN};;
    3.25                  *"error:"*)             cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
    3.26                  *"make["?*"]:"*"Stop.") cur_L=ERROR; cur_l=${CT_LOG_LEVEL_ERROR};;
    3.27                  *)                      cur_L="${LEVEL}"; cur_l="${level}";;
    3.28                esac
    3.29                l="`printf \"[%-5s]%*s%s%s\" \"${cur_L}\" \"${indent}\" \" \" \"${line}\"`"
    3.30                # There will always be a log file, be it /dev/null
    3.31 -              echo -e "${l}" >>"${CT_ACTUAL_LOG_FILE}"
    3.32 +              echo -e "${l}"
    3.33                if [ ${cur_l} -le ${max_level} ]; then
    3.34 -                  echo -e "\r${l}"
    3.35 +                  echo -e "\r${l}" >&6
    3.36                fi
    3.37                if [ "${CT_LOG_PROGRESS_BAR}" = "y" ]; then
    3.38 -                  str=`CT_DoDate +%s`
    3.39 -                  elapsed=$((str-(CT_STAR_DATE/(1000*1000*1000))))
    3.40 +                  elapsed=$((SECONDS+OFFSET))
    3.41                    [ ${CT_PROG_BAR_CPT} -eq 0  ] && bar="/"
    3.42                    [ ${CT_PROG_BAR_CPT} -eq 10 ] && bar="-"
    3.43                    [ ${CT_PROG_BAR_CPT} -eq 20 ] && bar="\\"
    3.44                    [ ${CT_PROG_BAR_CPT} -eq 30 ] && bar="|"
    3.45 -                  printf "\r[%02d:%02d] %s " $((elapsed/60)) $((elapsed%60)) "${bar}"
    3.46 +                  printf "\r[%02d:%02d] %s " $((elapsed/60)) $((elapsed%60)) "${bar}" >&6
    3.47                    CT_PROG_BAR_CPT=$(((CT_PROG_BAR_CPT+1)%40))
    3.48                fi
    3.49            done