diff --git a/CHANGELOG.md b/CHANGELOG.md index 53f95872..0b10e083 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,11 @@ ## Unreleased ### Added ### Changed + +* Update PGO build instructions in `INSTALL.md` + (https://codeberg.org/dnkl/foot/issues/418). + + ### Deprecated ### Removed ### Fixed diff --git a/INSTALL.md b/INSTALL.md index 1cb0d9a7..9fa651e1 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -65,6 +65,7 @@ In addition to the dev variant of the packages above, you need: * wayland protocols * ncurses (needed to generate terminfo) * scdoc (for man page generation) +* llvm (for PGO builds with Clang) * [tllist](https://codeberg.org/dnkl/tllist) [^1] A note on compilers; in general, foot runs **much** faster when @@ -184,21 +185,15 @@ slower!) binary. First, configure the build directory: ```sh -export CFLAGS="$CFLAGS -O3 -Wno-missing-profile" +export CFLAGS="$CFLAGS -O3" meson --buildtype=release --prefix=/usr -Db_lto=true ../.. ``` It is **very** important `-O3` is being used here, as GCC-10.1.x and later have a regression where PGO with `-O2` is **much** slower. -If you are using Clang instead of GCC, use the following `CFLAGS` instead: - -```sh -export CFLAGS="$CFLAGS -O3 \ - -Wno-ignored-optimization-argument \ - -Wno-profile-instr-out-of-date \ - -Wno-profile-instr-unprofiled" -``` +Clang users **must** add `-Wno-ignored-optimization-argument` to +`CFLAGS`. Then, tell meson we want to _generate_ profiling data, and build: @@ -234,6 +229,8 @@ We will use the `pgo` binary along with input corpus generated by `scripts/generate-alt-random-writes.py`: ```sh +./footclient --version +./foot --version tmp_file=$(mktemp) ../../scripts/generate-alt-random-writes \ --rows=67 \ @@ -253,7 +250,12 @@ tmp_file=$(mktemp) rm ${tmp_file} ``` -The snippet above first creates an (empty) temporary file. Then, it +The first step, running `./foot --version` and `./footclient +--version` might seem unnecessary, but is needed to ensure we have +_some_ profiling data for functions not covered by the PGO helper +binary. Without this, the final link phase will fail. + +The snippet above then creates an (empty) temporary file. Then, it runs a script that generates random escape sequences (if you cat `${tmp_file}` in a terminal, you’ll see random colored characters all over the screen). Finally, we feed the randomly generated escape @@ -271,14 +273,19 @@ This method requires a running Wayland session. We will use the script `scripts/generate-alt-random-writes.py`: ```sh +./footclient --version foot_tmp_file=$(mktemp) -./foot --config=/dev/null --term=xterm sh -c " --scroll --scroll-region --colors-regular --colors-bright --colors-256 --colors-rgb --attr-bold --attr-italic --attr-underline ${foot_tmp_file} && cat ${foot_tmp_file}" +./foot --config=/dev/null --term=xterm sh -c " --scroll --scroll-region --colors-regular --colors-bright --colors-256 --colors-rgb --attr-bold --attr-italic --attr-underline --sixel ${foot_tmp_file} && cat ${foot_tmp_file}" rm ${foot_tmp_file} ``` You should see a foot window open up, with random colored text. The window should close after ~1-2s. +The first step, `./footclient --version` might seem unnecessary, but +is needed to ensure we have _some_ profiling data for +`footclient`. Without this, the final link phase will fail. + ##### Use the generated PGO data diff --git a/PKGBUILD b/PKGBUILD index d5a99516..67894b80 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -14,37 +14,70 @@ pkgver() { } build() { + local compiler=other + local do_pgo=no + # makepkg uses -O2 by default, but we *really* want -O3 - # -Wno-missing-profile since we're not exercising everything when doing PGO builds - export CFLAGS+=" -O3 -Wno-missing-profile" + CFLAGS+=" -O3" + + # Figure out which compiler we're using, and whether or not to do PGO + case $(${CC-cc} --version) in + *GCC*) + compiler=gcc + do_pgo=yes + ;; + + *clang*) + compiler=clang + + # We need llvm to be able to manage the profiling data + if command -v llvm-profdata > /dev/null; then + do_pgo=yes + + # Meson adds -fprofile-correction, which Clang doesn't + # understand + CFLAGS+=" -Wno-ignored-optimization-argument" + fi + ;; + esac meson --prefix=/usr --buildtype=release --wrap-mode=nofallback -Db_lto=true .. - find -name "*.gcda" -delete - meson configure -Db_pgo=generate - ninja + if [[ ${do_pgo} == yes ]]; then + find -name "*.gcda" -delete + meson configure -Db_pgo=generate + ninja - script_options="--scroll --scroll-region --colors-regular --colors-bright --colors-256 --colors-rgb --attr-bold --attr-italic --attr-underline --sixel" + local script_options="--scroll --scroll-region --colors-regular --colors-bright --colors-256 --colors-rgb --attr-bold --attr-italic --attr-underline --sixel" - tmp_file=$(mktemp) + tmp_file=$(mktemp) - if [[ -v WAYLAND_DISPLAY ]]; then - ./foot \ - --config /dev/null \ - --term=xterm \ - sh -c "../scripts/generate-alt-random-writes.py ${script_options} ${tmp_file} && cat ${tmp_file}" - else - ../scripts/generate-alt-random-writes.py \ - --rows=67 \ - --cols=135 \ - ${script_options} \ - ${tmp_file} - ./pgo ${tmp_file} ${tmp_file} ${tmp_file} + if [[ -v WAYLAND_DISPLAY ]]; then + ./footclient --version + ./foot \ + --config /dev/null \ + --term=xterm \ + sh -c "../scripts/generate-alt-random-writes.py ${script_options} ${tmp_file} && cat ${tmp_file}" + else + ./footclient --version + ./foot --version + ../scripts/generate-alt-random-writes.py \ + --rows=67 \ + --cols=135 \ + ${script_options} \ + ${tmp_file} + ./pgo ${tmp_file} ${tmp_file} ${tmp_file} + fi + + rm "${tmp_file}" + + if [[ ${compiler} == clang ]]; then + llvm-profdata merge default_*profraw --output=default.profdata + fi + + meson configure -Db_pgo=use fi - rm "${tmp_file}" - - meson configure -Db_pgo=use ninja } diff --git a/client.c b/client.c index 975269b1..93dcc666 100644 --- a/client.c +++ b/client.c @@ -35,8 +35,10 @@ static const char * version_and_features(void) { static char buf[256]; - snprintf(buf, sizeof(buf), "version: %s %cime", - FOOT_VERSION, feature_ime() ? '+' : '-'); + snprintf(buf, sizeof(buf), "version: %s %cime %cpgo", + FOOT_VERSION, + feature_ime() ? '+' : '-', + feature_pgo() ? '+' : '-'); return buf; } diff --git a/foot-features.h b/foot-features.h index 8da22f6c..ae00c564 100644 --- a/foot-features.h +++ b/foot-features.h @@ -10,3 +10,12 @@ static inline bool feature_ime(void) return false; #endif } + +static inline bool feature_pgo(void) +{ +#if defined(FOOT_PGO_ENABLED) && FOOT_PGO_ENABLED + return true; +#else + return false; +#endif +} diff --git a/main.c b/main.c index 0941d3db..2c14d6d0 100644 --- a/main.c +++ b/main.c @@ -45,8 +45,10 @@ static const char * version_and_features(void) { static char buf[256]; - snprintf(buf, sizeof(buf), "version: %s %cime", - FOOT_VERSION, feature_ime() ? '+' : '-'); + snprintf(buf, sizeof(buf), "version: %s %cime %cpgo", + FOOT_VERSION, + feature_ime() ? '+' : '-', + feature_pgo() ? '+' : '-'); return buf; } diff --git a/meson.build b/meson.build index 01f27be9..9fbf99a6 100644 --- a/meson.build +++ b/meson.build @@ -24,6 +24,9 @@ add_project_arguments( (get_option('ime') ? ['-DFOOT_IME_ENABLED=1'] : []) + + (get_option('b_pgo') == 'use' + ? ['-DFOOT_PGO_ENABLED=1'] + : []) + cc.get_supported_arguments( ['-pedantic', '-fstrict-aliasing', @@ -114,16 +117,20 @@ version = custom_target( output: 'version.h', command: [generate_version_sh, meson.project_version(), '@SOURCE_ROOT@', '@OUTPUT@']) +common = static_library( + 'common', + 'log.c', 'log.h', + 'debug.c', 'debug.h', + 'xmalloc.c', 'xmalloc.h', + 'xsnprintf.c', 'xsnprintf.h' +) + misc = static_library( 'misc', - 'debug.c', 'debug.h', 'hsl.c', 'hsl.h', - 'log.c', 'log.h', 'macros.h', 'misc.c', 'misc.h', - 'uri.c', 'uri.h', - 'xmalloc.c', 'xmalloc.h', - 'xsnprintf.c', 'xsnprintf.h', + 'uri.c', 'uri.h' ) vtlib = static_library( @@ -137,7 +144,7 @@ vtlib = static_library( wl_proto_src + wl_proto_headers, version, dependencies: [libepoll, pixman, fcft, tllist, wayland_client], - link_with: misc, + link_with: [common, misc], ) pgolib = static_library( @@ -150,13 +157,15 @@ pgolib = static_library( link_with: vtlib, ) -executable( - 'pgo', - 'pgo/pgo.c', - wl_proto_src + wl_proto_headers, - dependencies: [math, threads, libepoll, pixman, wayland_client, fcft, tllist], - link_with: pgolib, -) +if get_option('b_pgo') == 'generate' + executable( + 'pgo', + 'pgo/pgo.c', + wl_proto_src + wl_proto_headers, + dependencies: [math, threads, libepoll, pixman, wayland_client, fcft, tllist], + link_with: pgolib, + ) +endif executable( 'foot', @@ -192,14 +201,11 @@ executable( executable( 'footclient', 'client.c', 'client-protocol.h', - 'debug.c', 'debug.h', 'foot-features.h', - 'log.c', 'log.h', 'macros.h', 'util.h', - 'xmalloc.c', 'xmalloc.h', - 'xsnprintf.c', 'xsnprintf.h', version, + link_with: common, install: true) if tic.found()