Skip to content

Makeself script slow for large archives in versions 2.4.2+ #344

@tonygoldman

Description

@tonygoldman

Use case

I am creating a makeself archive for deployment on nvidia jetson device using the following steps:

  • Download jetson sample rootfs from Nvidia
  • Chroot into the rootfs and install apt packages and pull dockers
  • Execute makeself to archive and compress the rootfs
  • Run makeself executable to flash the jetson device

Version 2.4.0

Makeself build takes 10 seconds and utilizes all cores simultaniously for compression.

In version 2.4.0 a new tar archive is piped directly to the compression program allowing fast and simultanious compression.

exec 3<> "$tmpfile"
( cd "$archdir" && ( tar $TAR_EXTRA -$TAR_ARGS - . | eval "$GZIP_CMD" >&3 ) ) || \
    { echo Aborting: archive directory not found or temporary file: "$tmpfile" could not be created.; exec 3>&-; rm -f "$tmpfile"; exit 1; }
exec 3>&- # try to close the archive

Version 2.4.2 - 2.5.0

Makeself build takes 140 seconds, and only a single core is utilized, except for 10 seconds near the end of the build.

In version 2.4.2+ an empty archive is updated in a loop for each file, unefficient for large archives.
Furthermore, compression only occurs later in the script, removing the advantage of simultanious archiving and compression.

tmparch="${TMPDIR:-/tmp}/mkself$$.tar"
(
    if test "$APPEND" = "y"; then
        tail -n "+$OLDSKIP" "$archname" | eval "$GUNZIP_CMD" > "$tmparch"
    fi
    cd "$archdir"
    # "Determining if a directory is empty"
    # https://www.etalabs.net/sh_tricks.html
    find . \
        \( \
        ! -type d \
        -o \
        \( -links 2 -exec sh -c '
            is_empty () (
                cd "$1"
                set -- .[!.]* ; test -f "$1" && return 1
                set -- ..?* ; test -f "$1" && return 1
                set -- * ; test -f "$1" && return 1
                return 0
            )
            is_empty "$0"' {} \; \
        \) \
        \) -print \
        | LC_ALL=C sort \
        | sed 's/./\\&/g' \
        | xargs $TAR $TAR_EXTRA --format $TAR_FORMAT -$TAR_ARGS "$tmparch"
) || {
    echo "ERROR: failed to create temporary archive: $tmparch"
    rm -f "$tmparch" "$tmpfile"
    exit 1
}

USIZE=`du $DU_ARGS "$tmparch" | awk '{print $1}'`

eval "$GZIP_CMD" <"$tmparch" >"$tmpfile" || {
    echo "ERROR: failed to create temporary file: $tmpfile"
    rm -f "$tmparch" "$tmpfile"
    exit 1
}
rm -f "$tmparch"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions