1{
2 lib,
3 stdenv,
4 fetchurl,
5 kernel,
6 kernelModuleMakeFlags,
7 elfutils,
8 python3,
9 perl,
10 newt,
11 slang,
12 asciidoc,
13 xmlto,
14 makeWrapper,
15 docbook_xsl,
16 docbook_xml_dtd_45,
17 libxslt,
18 flex,
19 bison,
20 pkg-config,
21 libunwind,
22 binutils-unwrapped,
23 libiberty,
24 audit,
25 libbfd,
26 libbfd_2_38,
27 libopcodes,
28 libopcodes_2_38,
29 libpfm,
30 libtraceevent,
31 openssl,
32 systemtap,
33 numactl,
34 zlib,
35 babeltrace,
36 withGtk ? false,
37 gtk2,
38 withZstd ? true,
39 zstd,
40 withLibcap ? true,
41 libcap,
42}:
43let
44 d3-flame-graph-templates = stdenv.mkDerivation rec {
45 pname = "d3-flame-graph-templates";
46 version = "4.1.3";
47
48 src = fetchurl {
49 url = "https://registry.npmjs.org/d3-flame-graph/-/d3-flame-graph-${version}.tgz";
50 sha256 = "sha256-W5/Vh5jarXUV224aIiTB2TnBFYT3naEIcG2945QjY8Q=";
51 };
52
53 installPhase = ''
54 install -D -m 0755 -t $out/share/d3-flame-graph/ ./dist/templates/*
55 '';
56 };
57in
58
59stdenv.mkDerivation {
60 pname = "perf-linux";
61 inherit (kernel) version src;
62
63 patches =
64 lib.optionals (lib.versionAtLeast kernel.version "5.10" && lib.versionOlder kernel.version "6.13")
65 [
66 # fix wrong path to dmesg
67 ./fix-dmesg-path.diff
68 ];
69
70 postPatch =
71 ''
72 # Linux scripts
73 patchShebangs scripts
74 patchShebangs tools/perf/check-headers.sh
75 ''
76 + lib.optionalString (lib.versionAtLeast kernel.version "6.3") ''
77 # perf-specific scripts
78 patchShebangs tools/perf/pmu-events
79 ''
80 + ''
81 cd tools/perf
82
83 for x in util/build-id.c util/dso.c; do
84 substituteInPlace $x --replace /usr/lib/debug /run/current-system/sw/lib/debug
85 done
86
87 ''
88 + lib.optionalString (lib.versionAtLeast kernel.version "5.8") ''
89 substituteInPlace scripts/python/flamegraph.py \
90 --replace "/usr/share/d3-flame-graph/d3-flamegraph-base.html" \
91 "${d3-flame-graph-templates}/share/d3-flame-graph/d3-flamegraph-base.html"
92
93 ''
94 + lib.optionalString (lib.versionAtLeast kernel.version "6.0") ''
95 patchShebangs pmu-events/jevents.py
96 '';
97
98 makeFlags =
99 [
100 "prefix=$(out)"
101 "WERROR=0"
102 "ASCIIDOC8=1"
103 ]
104 ++ kernelModuleMakeFlags
105 ++ lib.optional (!withGtk) "NO_GTK2=1"
106 ++ lib.optional (!withZstd) "NO_LIBZSTD=1"
107 ++ lib.optional (!withLibcap) "NO_LIBCAP=1";
108
109 hardeningDisable = [ "format" ];
110
111 # perf refers both to newt and slang
112 nativeBuildInputs = [
113 asciidoc
114 xmlto
115 docbook_xsl
116 docbook_xml_dtd_45
117 libxslt
118 flex
119 bison
120 libiberty
121 audit
122 makeWrapper
123 pkg-config
124 python3
125 ];
126
127 buildInputs =
128 [
129 elfutils
130 newt
131 slang
132 libtraceevent
133 libunwind
134 zlib
135 openssl
136 numactl
137 python3
138 perl
139 babeltrace
140 ]
141 ++ (
142 if (lib.versionAtLeast kernel.version "5.19") then
143 [
144 libbfd
145 libopcodes
146 ]
147 else
148 [
149 libbfd_2_38
150 libopcodes_2_38
151 ]
152 )
153 ++ lib.optional (lib.meta.availableOn stdenv.hostPlatform systemtap) systemtap.stapBuild
154 ++ lib.optional withGtk gtk2
155 ++ lib.optional withZstd zstd
156 ++ lib.optional withLibcap libcap
157 ++ lib.optional (lib.versionAtLeast kernel.version "5.8") libpfm
158 ++ lib.optional (lib.versionAtLeast kernel.version "6.0") python3.pkgs.setuptools
159 # Python 3.12 no longer includes distutils, not needed for 6.0 and newer.
160 ++
161 lib.optional
162 (!(lib.versionAtLeast kernel.version "6.0") && lib.versionAtLeast python3.version "3.12")
163 [
164 python3.pkgs.distutils
165 python3.pkgs.packaging
166 ];
167
168 env.NIX_CFLAGS_COMPILE = toString [
169 "-Wno-error=cpp"
170 "-Wno-error=bool-compare"
171 "-Wno-error=deprecated-declarations"
172 "-Wno-error=stringop-truncation"
173 ];
174
175 doCheck = false; # requires "sparse"
176
177 installTargets = [
178 "install"
179 "install-man"
180 ];
181
182 # TODO: Add completions based on perf-completion.sh
183 postInstall = ''
184 # Same as perf. Remove.
185 rm -f $out/bin/trace
186 '';
187
188 separateDebugInfo = true;
189
190 preFixup = ''
191 # Pull in 'objdump' into PATH to make annotations work.
192 # The embedded Python interpreter will search PATH to calculate the Python path configuration(Should be fixed by upstream).
193 # Add python.interpreter to PATH for now.
194 wrapProgram $out/bin/perf \
195 --prefix PATH : ${
196 lib.makeBinPath [
197 binutils-unwrapped
198 python3
199 ]
200 }
201 '';
202
203 meta = with lib; {
204 homepage = "https://perf.wiki.kernel.org/";
205 description = "Linux tools to profile with performance counters";
206 mainProgram = "perf";
207 maintainers = with maintainers; [ tobim ];
208 platforms = platforms.linux;
209 broken = kernel.kernelOlder "5";
210 };
211}