好的系统不需要自己优化
仅仅依靠前面两篇文章中提到的优化选项是不能够让你的系统运行地更快的。
而且如果自己水平不够的化,盲目优化,带来的后果可能是毁灭性的,所以耗费精力优化系统,得到很少的性能提升,是很愚蠢的。
主要是对env的定义和内核的配置,每个包都有可以删减的USE,去掉多余的选项对于使用KDE的桌面系统很重要。
env
首先创建一个路径/etc/portage/env
,在下面定义一些常用的变量。分为gcc和clang两大部分,对于使用PGO单独优化的包,其环境变量定义在portage的bashrc中。
O3
暴力优化第一步,大部分包开启O2
就够了,一些包甚至不能开启到这么高的优化等级,实际使用需要注意。
O3="-march=native -O3 -pipe"
COMMON_FLAGS="${O3}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
graphite
需要开启gcc的graphite
的USE,才能使用。
GRAPHITE="-fgraphite-identity -floop-nest-optimize"
COMMON_FLAGS="${COMMON_FLAGS} ${GRAPHITE}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
noplt
-fno-plt
Do not use the PLT for external function calls in position-independent code. Instead, load the callee address at call sites from the GOT and branch to it. This leads to more efficient code by eliminating PLT stubs and exposing GOT loads to optimizations. On architectures such as 32-bit x86 where PLT stubs expect the GOT pointer in a specific register, this gives more register allocation freedom to the compiler. Lazy binding requires use of the PLT; with -fno-plt all external symbols are resolved at load time.
Alternatively, the function attribute noplt can be used to avoid calls through the PLT for specific external functions.
In position-dependent code, a few targets also convert calls to functions that are marked to not use the PLT to use the GOT instead.
NOPLT="-fno-plt"
COMMON_FLAGS="${COMMON_FLAGS} ${NOPLT}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
seminterpos
可以加快链接库的速度,但是有可能会改变行为。
SEMINTERPOS="-fno-semantic-interposition"
COMMON_FLAGS="${COMMON_FLAGS} ${SEMINTERPOS}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
ipa-pta
对指针的静态优化,仅限于gcc,开启后需要更大的编译时内存和时间。
IPAPTA="-fipa-pta"
COMMON_FLAGS="${COMMON_FLAGS} ${IPAPTA}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
lto
对gcc使用lto,使用clang的包使用thinlto。
LTO="-flto=auto"
COMMON_FLAGS="${COMMON_FLAGS} ${LTO}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
LTO="-flto=thin"
COMMON_FLAGS="${COMMON_FLAGS} ${LTO}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
devirtlto
gcc开启lto后使用。
DEVIRTLTO="-fdevirtualize-at-ltrans"
COMMON_FLAGS="${COMMON_FLAGS} ${DEVIRTLTO}"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
package.env
仅作为例子。
Python
Python是portage的一个依赖,对python加点料是很有必要的,每次更新系统起码能节省一两秒的时间。
可以参考Fedora的文章
USE
编辑python的use,vim package.use/dev-lang
,加入
dev-lang/python pgo
C Flags
编辑/etc/portage/package.env/dev-lang
,加入
dev-lang/python O3 graphite noplt seminterpos ipapta lto devirtlto
然后重新编译python:emerge -1 python
bashrc
如果O3,LTO这些已经足够激进的优化还不能满足你尝试黑魔法的心,你可以使用PGO进行优化,这个也是Gentoo的portage很容易就可以实现的一项操作。
目前的EAPI不能对包开启统一的PGO特性,和lto一样,并不是所有的包都可以开启PGO优化,而且并不能够保证PGO的两个阶段就一定能够正常工作或者有明显的性能提升。所以还是使用环境变量的方法,编译两次,中间需要自己进行测试并把gdata写入对应的目录中。
需要事先建立/var/tmp/pgo
文件夹,或者在脚本中加入mkdir -p ${PGO_DIR}
。
PGO_DIR="/var/tmp/pgo"
PROFILE_DIR="${PGO_DIR}/${CATEGORY}/${P}"
下面是完整的脚本示例,需要根据你想进行PGO优化的PN
或者CATEGORY
填入,并且最后的chown
操作需要修改为运行pgo阶段一的程序用户。
#!/bin/bash
PGO_DIR="/var/tmp/pgo"
PROFILE_DIR="${PGO_DIR}/${CATEGORY}/${P}"
PROFILABLE=0
CFLAGS_PROFILE_GEN="-fprofile-generate=${PROFILE_DIR} --coverage"
CFLAGS_PROFILE_USE="-fprofile-use=${PROFILE_DIR} -fprofile-correction"
CXXFLAGS_PROFILE_GEN="-fprofile-generate=${PROFILE_DIR} --coverage"
CXXFLAGS_PROFILE_USE="-fprofile-use=${PROFILE_DIR} -fprofile-correction"
LDFLAGS_PROFILE_GEN="--coverage"
CFLAGS_CUSTOM=""
LDFLAGS_CUSTOM=""
if [ "${EBUILD_PHASE}" == "unpack" ]
then
if type epatch_user >& /dev/null; then
cd "${S}"
epatch_user
fi
if [[ "$CFLAGS" != *"gdb"* && "$CXXFLAGS" != *"gdb"* ]] && [[ "${IUSE}" != *"pgo"* && "${USE}" != *"pgo"* ]]
then
case "${PN}" in
telegram-desktop | kwin | kio | plasma-workspace | dxvk | mesa | ffmpeg)
elog "Portage will try to build ${CATEGORY}/${PN} with PGO."
if [ -d "${PROFILE_DIR}" ]
then
elog "Portage will use the analysis that is stored at ${PROFILE_DIR}."
CFLAGS="${CFLAGS} ${CFLAGS_CUSTOM} ${CFLAGS_PROFILE_USE}"
CXXFLAGS="${CXXFLAGS} ${CXXFLAGS_CUSTOM} ${CXXFLAGS_PROFILE_USE}"
LDFLAGS="${LDFLAGS} ${LDFLAGS_CUSTOM}"
else
elog "Running with PGO for the first time. Use ${P} before you recompile it."
CFLAGS="${CFLAGS} ${CFLAGS_CUSTOM} ${CFLAGS_PROFILE_GEN}"
CXXFLAGS="${CXXFLAGS} ${CXXFLAGS_CUSTOM} ${CXXFLAGS_PROFILE_GEN}"
LDFLAGS="${LDFLAGS} ${LDFLAGS_CUSTOM} ${LDFLAGS_PROFILE_GEN}"
fi
;;
esac
case "${CATEGORY}" in
null)
elog "Portage will try to build ${CATEGORY}/${PN} with PGO."
if [ -d "${PROFILE_DIR}" ]
then
elog "Portage will use the analysis that is stored at ${PROFILE_DIR}."
CFLAGS="${CFLAGS} ${CFLAGS_CUSTOM} ${CFLAGS_PROFILE_USE}"
CXXFLAGS="${CXXFLAGS} ${CXXFLAGS_CUSTOM} ${CXXFLAGS_PROFILE_USE}"
LDFLAGS="${LDFLAGS} ${LDFLAGS_CUSTOM}"
else
elog "Running with PGO for the first time. Use ${P} before you recompile it."
CFLAGS="${CFLAGS} ${CFLAGS_CUSTOM} ${CFLAGS_PROFILE_GEN}"
CXXFLAGS="${CXXFLAGS} ${CXXFLAGS_CUSTOM} ${CXXFLAGS_PROFILE_GEN}"
LDFLAGS="${LDFLAGS} ${LDFLAGS_CUSTOM} ${LDFLAGS_PROFILE_GEN}"
fi
;;
esac
#PGO might exist in IUSE but the user may want it or not. Print the appropriate message.
elif [[ "${IUSE}" == *"pgo"* ]]
then
local PGO_WARN_MSG="IUSE array of ${CATEGORY}/${PN} contains pgo,"
local PGO_HANDLE_MSG="It is best to leave ${CATEGORY}/${P} ebuild handle this."
if [[ "${USE}" == *"pgo"* ]]
then
ewarn "${PGO_WARN_MSG} and it's enabled."
ewarn "${PGO_HANDLE_MSG}"
elif [[ "${USE}" != *"pgo"* ]]
then
ewarn "${PGO_WARN_MSG} but the user disabled this USE flag."
ewarn "${PGO_HANDLE_MSG}"
fi
fi
fi
if [ "${EBUILD_PHASE}" == "pre_src_prepare" ]
then
[[ ${EAPI:-0} == [012345] ]] || return
if ! type estack_push > /dev/null 2>&1; then
local estack_names="eshopts_push eshopts_pop evar_push evar_push_set evar_pop estack_push estack_pop"
source <(awk "/^# @(FUNCTION|VARIABLE): / { p = 0 } /^# @(FUNCTION|VARIABLE): (${estack_names// /|})\$/ { p = 1 } p { print }" ${PORTDIR}/eclass/estack.eclass)
fi
if ! type epatch_user > /dev/null 2>&1; then
local epatch_names="EPATCH_SOURCE EPATCH_USER_SOURCE epatch_user_death_notice epatch_user epatch"
source <(awk "/^# @(FUNCTION|VARIABLE): / { p = 0 } /^# @(FUNCTION|VARIABLE): (${epatch_names// /|})\$/ { p = 1 } p { print }" ${PORTDIR}/eclass/epatch.eclass)
fi
epatch_user
for name in $epatch_names; do
unset $name
done
for name in $estack_names; do
unset $name
done
fi
if [ "${EBUILD_PHASE}" == "postinst" ]
then
#if PGO was applied, test if it succeeded and chown the PROFILE_DIR
if [[ "$PROFILABLE" == 1 ]] ; then
for i in $(equery f "${PN}" | grep "bin/");
do
if [[ -z $(strings "${i}" | grep profiling) ]]; then
ewarn "${i} isn't making use of PGO while such cflags were applied to ${CATEGORY}/${P}"
else
elog "${i} is making use of PGO"
fi
done
for i in $(equery f "${PN}" | grep "*.so");
do
if [[ -z $(strings "${i}" | grep profiling) ]]; then
ewarn "${i} isn't making use of PGO while such cflags were applied to ${CATEGORY}/${P}."
else
elog "${i} is making use of PGO."
fi
done
fi
#Normal user should be able to "write" here the statistical analysis needed for PGO
# TODO: What about other users?
chown -R oripoin:oripoin "${PGO_DIR}"
# TODO: pgo use env
chmod -R 777 "${PGO_DIR}"
fi