working PGO

This commit is contained in:
2025-12-20 23:07:30 -06:00
parent 30ddc39ed5
commit 69ada12884
10 changed files with 190 additions and 33 deletions

16
Jenkinsfile vendored
View File

@@ -39,14 +39,16 @@ pipeline {
stage('build ffmpeg on darwin') { stage('build ffmpeg on darwin') {
matrix { matrix {
axes { axes {
axis { name 'OPT_LTO'; values 'OPT=0 LTO=OFF', 'OPT=3 LTO=ON' } axis { name 'COMP_OPTS'; values
axis { name 'STATIC'; values 'ON', 'OFF' } 'OPT=0 LTO=OFF STATIC=OFF',
'OPT=2 LTO=OFF STATIC=ON',
'OPT=3 LTO=ON STATIC=ON PGO=ON' }
} }
stages { stages {
stage('build on darwin ') { stage('build on darwin ') {
agent { label "darwin" } agent { label "darwin" }
steps { steps {
sh "${OPT_LTO} ./scripts/build.sh" sh "${COMP_OPTS} ./scripts/build.sh"
archiveArtifacts allowEmptyArchive: true, artifacts: 'gitignore/package/*.tar.xz', defaultExcludes: false archiveArtifacts allowEmptyArchive: true, artifacts: 'gitignore/package/*.tar.xz', defaultExcludes: false
} }
} }
@@ -58,15 +60,17 @@ pipeline {
axes { axes {
axis { name 'ARCH'; values 'armv8-a', 'x86-64-v3' } axis { name 'ARCH'; values 'armv8-a', 'x86-64-v3' }
axis { name 'DISTRO'; values 'ubuntu', 'fedora', 'debian', 'archlinux' } axis { name 'DISTRO'; values 'ubuntu', 'fedora', 'debian', 'archlinux' }
axis { name 'OPT_LTO'; values 'OPT=0 LTO=OFF', 'OPT=3 LTO=ON' } axis { name 'COMP_OPTS'; values
axis { name 'STATIC'; values 'ON', 'OFF' } 'OPT=0 LTO=OFF STATIC=OFF',
'OPT=2 LTO=OFF STATIC=ON',
'OPT=3 LTO=ON STATIC=ON PGO=ON' }
} }
stages { stages {
stage('build ffmpeg on linux using docker') { stage('build ffmpeg on linux using docker') {
agent { label "linux && ${ARCH}" } agent { label "linux && ${ARCH}" }
steps { steps {
withDockerCreds { withDockerCreds {
sh "${OPT_LTO} ./scripts/build_with_docker.sh ${DISTRO}" sh "${COMP_OPTS} ./scripts/build_with_docker.sh ${DISTRO}"
archiveArtifacts allowEmptyArchive: true, artifacts: 'gitignore/package/*.tar.xz', defaultExcludes: false archiveArtifacts allowEmptyArchive: true, artifacts: 'gitignore/package/*.tar.xz', defaultExcludes: false
} }
} }

View File

@@ -101,8 +101,7 @@ set_compile_opts() {
fi fi
CMAKE_FLAGS+=("-DCMAKE_LINKER=${USE_LD}") CMAKE_FLAGS+=("-DCMAKE_LINKER=${USE_LD}")
local compilerDir="${LOCAL_PREFIX}/compiler-tools" local compilerDir="${LOCAL_PREFIX}/compiler-tools"
test -d "${compilerDir}" && rm -rf "${compilerDir}" recreate_dir "${compilerDir}" || return 1
mkdir -p "${compilerDir}"
# real:gnu:clang:generic # real:gnu:clang:generic
local compilerMap="\ local compilerMap="\
${CC}:gcc:clang:cc ${CC}:gcc:clang:cc
@@ -166,6 +165,20 @@ exec \"${realT}\" ${addFlag} \"\$@\"" >"${compilerDir}/${genericT}"
# TODO use cygpath for windows # TODO use cygpath for windows
CPPFLAGS_ARR+=("-I${PREFIX}/include") CPPFLAGS_ARR+=("-I${PREFIX}/include")
# if PGO is enabled, first build run will be to generate
# second run will be to use generated profdata
if [[ ${PGO} == 'ON' ]]; then
if [[ ${PGO_RUN} == 'generate' ]]; then
local pgoFlag="-fprofile-generate"
CFLAGS_ARR+=("${pgoFlag}")
LDFLAGS_ARR+=("${pgoFlag}")
else
local pgoFlag="-fprofile-use=${PGO_PROFDATA}"
CFLAGS_ARR+=("${pgoFlag}")
LDFLAGS_ARR+=("${pgoFlag}")
fi
fi
# enabling link-time optimization # enabling link-time optimization
if [[ ${LTO} == 'ON' ]]; then if [[ ${LTO} == 'ON' ]]; then
LTO_FLAG='-flto=full' LTO_FLAG='-flto=full'
@@ -539,6 +552,14 @@ FB_FUNC_NAMES+=('build')
# shellcheck disable=SC2034 # shellcheck disable=SC2034
FB_FUNC_DESCS['build']='build ffmpeg with the desired configuration' FB_FUNC_DESCS['build']='build ffmpeg with the desired configuration'
build() { build() {
# if PGO is enabled, build will call build
# only want to recursively build on the first run
if [[ ${PGO} == 'ON' && ${PGO_RUN} != 'generate' ]]; then
PGO_RUN='generate' build || return 1
# will need to reset compile opts
unset FB_COMPILE_OPTS_SET
fi
set_compile_opts || return 1 set_compile_opts || return 1
for build in ${ENABLE}; do for build in ${ENABLE}; do
@@ -547,9 +568,16 @@ build() {
unset REQUIRES_REBUILD unset REQUIRES_REBUILD
done done
do_build ffmpeg || return 1 do_build ffmpeg || return 1
# skip packaging on PGO generate run
if [[ ${PGO} == 'ON' && ${PGO_RUN} == 'generate' ]]; then
PATH="${PREFIX}/bin:${PATH}" gen_profdata
return $?
fi
local ffmpegBin="${PREFIX}/bin/ffmpeg" local ffmpegBin="${PREFIX}/bin/ffmpeg"
# run ffmpeg to show completion # run ffmpeg to show completion
"${ffmpegBin}" -version "${ffmpegBin}" -version || return 1
# suggestion for path # suggestion for path
hash -r hash -r

View File

@@ -11,8 +11,7 @@ DOCKER_WORKDIR='/workdir'
set_docker_run_flags() { set_docker_run_flags() {
local cargo_git="${IGN_DIR}/cargo/git" local cargo_git="${IGN_DIR}/cargo/git"
local cargo_registry="${IGN_DIR}/cargo/registry" local cargo_registry="${IGN_DIR}/cargo/registry"
test -d "${cargo_git}" || mkdir -p "${cargo_git}" ensure_dir "${cargo_git}" "${cargo_registry}"
test -d "${cargo_registry}" || mkdir -p "${cargo_registry}"
DOCKER_RUN_FLAGS=( DOCKER_RUN_FLAGS=(
--rm --rm
-v "${cargo_git}:/root/.cargo/git" -v "${cargo_git}:/root/.cargo/git"

View File

@@ -35,13 +35,13 @@ set_efg_opts() {
sudo ln -sf "${SCRIPT_DIR}/efg.sh" \ sudo ln -sf "${SCRIPT_DIR}/efg.sh" \
"${EFG_INSTALL_PATH}" || return 1 "${EFG_INSTALL_PATH}" || return 1
echo_pass "succesfull install" echo_pass "succesfull install"
exit 0 return ${FUNC_EXIT_SUCCESS}
;; ;;
U) U)
echo_warn "attempting uninstall" echo_warn "attempting uninstall"
sudo rm "${EFG_INSTALL_PATH}" || return 1 sudo rm "${EFG_INSTALL_PATH}" || return 1
echo_pass "succesfull uninstall" echo_pass "succesfull uninstall"
exit 0 return ${FUNC_EXIT_SUCCESS}
;; ;;
i) i)
if [[ $# -lt 2 ]]; then if [[ $# -lt 2 ]]; then
@@ -126,8 +126,7 @@ efg_segment() {
local segmentBitrates=() local segmentBitrates=()
# clean workspace # clean workspace
test -d "${EFG_DIR}" && rm -rf "${EFG_DIR}" recreate_dir "${EFG_DIR}" || return 1
mkdir -p "${EFG_DIR}"
# split up video into segments based on start times # split up video into segments based on start times
for ((time = 0; time < duration; time += timeBetweenSegments)); do for ((time = 0; time < duration; time += timeBetweenSegments)); do
@@ -245,8 +244,14 @@ efg() {
# encode N highest-bitrate segments # encode N highest-bitrate segments
ENCODE_SEGMENTS=5 ENCODE_SEGMENTS=5
set_efg_opts "$@" || return 1 set_efg_opts "$@"
test -d "${EFG_DIR}" || mkdir "${EFG_DIR}" local ret=$?
if [[ ${ret} -eq ${FUNC_EXIT_SUCCESS} ]]; then
return 0
elif [[ ${ret} -ne 0 ]]; then
return ${ret}
fi
ensure_dir "${EFG_DIR}"
GRAIN_LOG="${EFG_DIR}/${LOW}-${STEP}-${HIGH}-grains.txt" GRAIN_LOG="${EFG_DIR}/${LOW}-${STEP}-${HIGH}-grains.txt"

View File

@@ -99,11 +99,11 @@ get_encode_versions() {
# shellcheck disable=SC2155 # shellcheck disable=SC2155
local output="$(ffmpeg -version 2>&1)" local output="$(ffmpeg -version 2>&1)"
while read -r line; do while read -r line; do
if line_contains "${line}" 'ffmpeg='; then if line_starts_with "${line}" 'ffmpeg='; then
ffmpegVersion="${line}" ffmpegVersion="${line}"
elif line_contains "${line}" 'libsvtav1_psy=' || line_contains "${line}" 'libsvtav1='; then elif line_starts_with "${line}" 'libsvtav1'; then
videoEncVersion="${line}" videoEncVersion="${line}"
elif line_contains "${line}" 'libopus='; then elif line_starts_with "${line}" 'libopus='; then
audioEncVersion="${line}" audioEncVersion="${line}"
fi fi
done <<<"${output}" done <<<"${output}"
@@ -188,25 +188,25 @@ set_encode_opts() {
while getopts "${opts}" flag; do while getopts "${opts}" flag; do
case "${flag}" in case "${flag}" in
u) u)
encode_update encode_update || return 1
exit $? return ${FUNC_EXIT_SUCCESS}
;; ;;
I) I)
echo_warn "attempting install" echo_warn "attempting install"
sudo ln -sf "${SCRIPT_DIR}/encode.sh" \ sudo ln -sf "${SCRIPT_DIR}/encode.sh" \
"${ENCODE_INSTALL_PATH}" || return 1 "${ENCODE_INSTALL_PATH}" || return 1
echo_pass "succesfull install" echo_pass "succesfull install"
exit 0 return ${FUNC_EXIT_SUCCESS}
;; ;;
U) U)
echo_warn "attempting uninstall" echo_warn "attempting uninstall"
sudo rm "${ENCODE_INSTALL_PATH}" || return 1 sudo rm "${ENCODE_INSTALL_PATH}" || return 1
echo_pass "succesfull uninstall" echo_pass "succesfull uninstall"
exit 0 return ${FUNC_EXIT_SUCCESS}
;; ;;
v) v)
get_encode_versions print get_encode_versions print || return 1
exit $? return ${FUNC_EXIT_SUCCESS}
;; ;;
i) i)
if [[ $# -lt 2 ]]; then if [[ $# -lt 2 ]]; then
@@ -253,7 +253,7 @@ set_encode_opts() {
if ! is_positive_integer "${OPTARG}" || test ${OPTARG} -gt 63; then if ! is_positive_integer "${OPTARG}" || test ${OPTARG} -gt 63; then
echo_fail "${OPTARG} is not a valid CRF value (0-63)" echo_fail "${OPTARG} is not a valid CRF value (0-63)"
encode_usage encode_usage
exit 1 return 1
fi fi
CRF="${OPTARG}" CRF="${OPTARG}"
OPTS_USED=$((OPTS_USED + 2)) OPTS_USED=$((OPTS_USED + 2))
@@ -471,6 +471,12 @@ FB_FUNC_NAMES+=('encode')
# shellcheck disable=SC2034 # shellcheck disable=SC2034
FB_FUNC_DESCS['encode']='encode a file using libsvtav1_psy and libopus' FB_FUNC_DESCS['encode']='encode a file using libsvtav1_psy and libopus'
encode() { encode() {
set_encode_opts "$@" || return 1 set_encode_opts "$@"
local ret=$?
if [[ ${ret} -eq ${FUNC_EXIT_SUCCESS} ]]; then
return 0
elif [[ ${ret} -ne 0 ]]; then
return ${ret}
fi
gen_encode_script || return 1 gen_encode_script || return 1
} }

View File

@@ -126,3 +126,41 @@ get_stream_lang() {
-of default=noprint_wrappers=1:nokey=1 \ -of default=noprint_wrappers=1:nokey=1 \
"${file}" "${file}"
} }
gen_video() {
local outFile="$1"
local addFlags=()
shift
local vf="format=yuv420p10le"
for arg in "$@"; do
case "${arg}" in
'1080p') resolution='1920x1080' ;;
'2160p') resolution='3840x2160' ;;
'grain=yes') vf+=",noise=alls=15:allf=t+u" ;;
'hdr=yes')
vf+=",setparams=color_primaries=bt2020:color_trc=smpte2084:colorspace=bt2020nc"
addFlags+=(
-color_primaries bt2020
-color_trc smpte2084
-colorspace bt2020nc
-metadata:s:v:0 "mastering_display_metadata=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1)"
-metadata:s:v:0 "content_light_level=1000,400"
)
;;
*) echo_fail "bad arg ${arg}" && return 1 ;;
esac
done
ffmpeg -y \
-hide_banner \
-f lavfi \
-i "testsrc2=size=${resolution}:rate=24:duration=5" \
-vf "${vf}" \
-c:v ffv1 \
-level 3 \
-g 1 \
-color_range tv \
"${addFlags[@]}" \
"${outFile}"
}

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
check_for_package_cfg() { check_for_package_cfg() {
local requiredCfg='ON:ON:3' local requiredCfg='ON:ON:ON:3'
local currentCfg="${STATIC}:${LTO}:${OPT}" local currentCfg="${STATIC}:${LTO}:${PGO}:${OPT}"
if [[ ${currentCfg} == "${requiredCfg}" ]]; then if [[ ${currentCfg} == "${requiredCfg}" ]]; then
return 0 return 0
else else
@@ -14,12 +14,10 @@ FB_FUNC_NAMES+=('package')
FB_FUNC_DESCS['package']='package ffmpeg build' FB_FUNC_DESCS['package']='package ffmpeg build'
package() { package() {
local pkgDir="${IGN_DIR}/package" local pkgDir="${IGN_DIR}/package"
test -d "${pkgDir}" && rm -rf "${pkgDir}" recreate_dir "${pkgDir}" || return 1
check_for_package_cfg || return 0 check_for_package_cfg || return 0
echo_info "packaging" echo_info "packaging"
mkdir "${pkgDir}" || return 1
set_compile_opts || return 1 set_compile_opts || return 1
cp "${PREFIX}/bin/ff"* "${pkgDir}/" cp "${PREFIX}/bin/ff"* "${pkgDir}/"

59
lib/pgo.sh Normal file
View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
PGO_DIR="${IGN_DIR}/pgo"
PGO_PROFDATA="${PGO_DIR}/prof.profdata"
gen_profdata() {
recreate_dir "${PGO_DIR}" || return 1
cd "${PGO_DIR}" || return 1
setup_pgo_clips || return 1
for vid in *.mkv; do
local args=()
# add precalculated grain amount based off of filename
line_contains "${vid}" 'grain' && args+=(-g 16)
# make fhd preset 2
line_contains "${vid}" 'fhd' && args+=(-P 2)
LLVM_PROFILE_FILE="${PGO_DIR}/default_%p.profraw" \
encode -i "${vid}" "${args[@]}" "encoded-${vid}" || return 1
done
# merge profraw into profdata
local mergeCmd=()
# darwin needs special invoke
if is_darwin; then
mergeCmd+=(xcrun)
fi
mergeCmd+=(
llvm-profdata
merge
"--output=${PGO_PROFDATA}"
)
"${mergeCmd[@]}" default*.profraw || return 1
return 0
}
setup_pgo_clips() {
local clips=(
"fhd-grainy.mkv 1080p,grain=yes"
"uhd.mkv 2160p"
"uhd-hdr.mkv 2160p,hdr=yes"
)
for clip in "${clips[@]}"; do
local genVid genVidArgs pgoFile genVidArgsArr
IFS=' ' read -r genVid genVidArgs <<<"${clip}"
# pgo path is separate
pgoFile="${PGO_DIR}/${genVid}"
genVid="${TMP_DIR}/${genVid}"
# create array of args split with ,
genVidArgsArr=(${genVidArgs//,/ })
# create generated vid without any profiling if needed
test -f "${genVid}" ||
LLVM_PROFILE_FILE='/dev/null' gen_video "${genVid}" "${genVidArgsArr[@]}" || return 1
# and move to the pgo directory
test -f "${pgoFile}" ||
cp "${genVid}" "${pgoFile}" || return 1
done
}

View File

@@ -366,3 +366,18 @@ get_pkgconfig_version() {
local pkg="$1" local pkg="$1"
pkg-config --modversion "${pkg}" pkg-config --modversion "${pkg}"
} }
recreate_dir() {
local dirs=("$@")
for dir in "${dirs[@]}"; do
test -d "${dir}" && rm -rf "${dir}"
mkdir -p "${dir}" || return 1
done
}
ensure_dir() {
local dirs=("$@")
for dir in "${dirs[@]}"; do
test -d "${dir}" || mkdir -p "${dir}" || return 1
done
}

View File

@@ -15,6 +15,11 @@ DOCKER_DIR="${IGN_DIR}/docker"
PATCHES_DIR="${REPO_DIR}/patches" PATCHES_DIR="${REPO_DIR}/patches"
export REPO_DIR IGN_DIR TMP_DIR DL_DIR BUILD_DIR CCACHE_DIR DOCKER_DIR PATCHES_DIR export REPO_DIR IGN_DIR TMP_DIR DL_DIR BUILD_DIR CCACHE_DIR DOCKER_DIR PATCHES_DIR
# some functions need a way to signal early
# returns instead of failures, so if a function
# returns ${FUNC_EXIT_SUCCESS}, stop processing
test -v FUNC_EXIT_SUCCESS || readonly FUNC_EXIT_SUCCESS=9
# make paths if needed # make paths if needed
IGN_DIRS=( IGN_DIRS=(
"${TMP_DIR}" "${TMP_DIR}"