Optimize Your system the stupid way

好的系统不需要自己优化

仅仅依靠前面两篇文章中提到的优化选项是不能够让你的系统运行地更快的。

而且如果自己水平不够的化,盲目优化,带来的后果可能是毁灭性的,所以耗费精力优化系统,得到很少的性能提升,是很愚蠢的。

主要是对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
知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
上一篇
下一篇