Last active
September 19, 2025 05:34
-
-
Save ConnorNelson/af7ea0945dab81921ed6522dc840b701 to your computer and use it in GitHub Desktop.
Compare disassembly of different optimization levels of various packages in nixpkgs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| description = "Pick-any package with selectable -O* (without rebuilding the world)"; | |
| inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; | |
| outputs = | |
| { self, nixpkgs }: | |
| let | |
| system = "x86_64-linux"; | |
| pkgs = import nixpkgs { inherit system; }; | |
| lib = pkgs.lib; | |
| mkWithCFlags = | |
| flags: drv: | |
| if lib.isDerivation drv then | |
| drv.overrideAttrs (old: { | |
| NIX_CFLAGS_COMPILE = lib.concatStringsSep " " ( | |
| lib.optional (old ? NIX_CFLAGS_COMPILE) old.NIX_CFLAGS_COMPILE ++ flags | |
| ); | |
| }) | |
| else | |
| drv; | |
| mkLevel = flags: lib.mapAttrs (_: mkWithCFlags flags) pkgs; | |
| levels = { | |
| O0 = [ "-O0" "-frecord-gcc-switches" ]; | |
| O1 = [ "-O1" "-frecord-gcc-switches" ]; | |
| O2 = [ "-O2" "-frecord-gcc-switches" ]; | |
| O3 = [ "-O3" "-frecord-gcc-switches" ]; | |
| Og = [ "-Og" "-frecord-gcc-switches" ]; | |
| Os = [ "-Os" "-frecord-gcc-switches" ]; | |
| Ofast = [ "-Ofast" "-frecord-gcc-switches" ]; | |
| }; | |
| opt = { | |
| O0 = mkLevel levels.O0; | |
| O1 = mkLevel levels.O1; | |
| O2 = mkLevel levels.O2; | |
| O3 = mkLevel levels.O3; | |
| Og = mkLevel levels.Og; | |
| Os = mkLevel levels.Os; | |
| Ofast = mkLevel levels.Ofast; | |
| }; | |
| odis = pkgs.writeShellApplication { | |
| name = "odis"; | |
| runtimeInputs = [ | |
| pkgs.nix # to run `nix build` | |
| pkgs.binutils # objdump | |
| pkgs.gawk # awk | |
| pkgs.gnugrep # grep (not strictly required but handy) | |
| pkgs.coreutils # head/sed/cut etc. | |
| pkgs.icdiff # pretty diff when two levels given | |
| ]; | |
| text = '' | |
| set -euo pipefail | |
| usage() { | |
| cat <<EOF | |
| Usage: | |
| odis -p <package> [-b <bin>] [-f <func>] [-n <lines>] <Olevel> [<Olevel2>] | |
| Examples: | |
| odis -p curl O0 | |
| odis -p curl O3 | |
| odis -p wget -f main O0 O3 | |
| odis -p coreutils -b ls Os O2 | |
| Flags: | |
| -p Nix package attr name (required), e.g. curl, wget, coreutils | |
| -b Binary name (defaults to package name), e.g. ls for coreutils | |
| -f Function to disassemble (default: main) | |
| -n Number of lines to print (default: 40) | |
| Notes: | |
| * Uses .#opt.<Olevel>.<package> from this flake. | |
| * Output is Intel syntax, .text only, no addresses/hex, no headers. | |
| * With two levels, shows an icdiff side-by-side diff. | |
| EOF | |
| } | |
| PKG="" | |
| BIN="" | |
| FUNC="main" | |
| LINES=20 | |
| while getopts ":p:b:f:n:h" opt; do | |
| case "$opt" in | |
| p) PKG="$OPTARG" ;; | |
| b) BIN="$OPTARG" ;; | |
| f) FUNC="$OPTARG" ;; | |
| n) LINES="$OPTARG" ;; | |
| h) usage; exit 0 ;; | |
| *) usage; exit 1 ;; | |
| esac | |
| done | |
| shift $((OPTIND-1)) | |
| if [ -z "''${PKG}" ]; then | |
| echo "error: -p <package> is required" >&2 | |
| usage; exit 1 | |
| fi | |
| if [ -z "''${BIN:-}" ]; then | |
| BIN="$PKG" | |
| fi | |
| if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then | |
| usage; exit 1 | |
| fi | |
| O1="$1" | |
| O2="''${2-}" | |
| build_path() { | |
| local level="$1" | |
| nix build ".#opt.$level.$PKG.bin" --print-out-paths 2>/dev/null || \ | |
| nix build ".#opt.$level.$PKG" --print-out-paths | |
| } | |
| dump() { | |
| # dump first $LINES lines of $FUNC, clean, and silence SIGPIPE noise | |
| local level="$1" | |
| local out | |
| out="$(build_path "$level")" | |
| objdump -d -M intel --section=.text --disassemble="$FUNC" \ | |
| --no-addresses --no-show-raw-insn "$out/bin/$BIN" 2>/dev/null \ | |
| | awk '/^Disassembly of section .text:/{f=1;next} f' \ | |
| | head -n "$LINES" | |
| } | |
| if [ -n "$O2" ]; then | |
| icdiff <(dump "$O1") <(dump "$O2") | |
| else | |
| dump "$O1" | |
| fi | |
| ''; | |
| }; | |
| in | |
| { | |
| packages.${system} = pkgs // { | |
| inherit opt odis; | |
| }; | |
| devShells.${system}.default = pkgs.mkShell { | |
| packages = with pkgs; [ | |
| icdiff | |
| binutils | |
| gawk | |
| gnugrep | |
| coreutils | |
| # nix | |
| odis | |
| ]; | |
| shellHook = '' | |
| echo "Try: odis -p curl O0 O3" | |
| ''; | |
| }; | |
| }; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This was mostly generated by ChatGPT.