From: "Lorenzo Stoakes (ARM)" <ljs@kernel.org>
To: "Linus Torvalds" <torvalds@linux-foundation.org>,
"Nathan Chancellor" <nathan@kernel.org>,
"Nicolas Schier" <nsc@kernel.org>,
"Nick Desaulniers" <ndesaulniers@google.com>,
"Bill Wendling" <morbo@google.com>,
"Justin Stitt" <justinstitt@google.com>,
"Masahiro Yamada" <masahiroy@kernel.org>,
"Alexey Gladkov" <legion@kernel.org>,
"Thomas Gleixner" <tglx@kernel.org>,
"Ingo Molnar" <mingo@redhat.com>,
"Borislav Petkov" <bp@alien8.de>,
"Dave Hansen" <dave.hansen@linux.intel.com>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
"Paul Walmsley" <pjw@kernel.org>,
"Palmer Dabbelt" <palmer@dabbelt.com>,
"Albert Ou" <aou@eecs.berkeley.edu>,
"Alexandre Ghiti" <alex@ghiti.fr>,
"Arnd Bergmann" <arnd@arndb.de>,
"Catalin Marinas" <catalin.marinas@arm.com>,
"Will Deacon" <will@kernel.org>,
"Mark Rutland" <mark.rutland@arm.com>,
"Ard Biesheuvel" <ardb@kernel.org>,
"Ilias Apalodimas" <ilias.apalodimas@linaro.org>,
"Josh Poimboeuf" <jpoimboe@kernel.org>,
"Peter Zijlstra" <peterz@infradead.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Tamir Duberstein" <tamird@kernel.org>,
"Alexandre Courbot" <acourbot@nvidia.com>,
"Onur Özkan" <work@onurozkan.dev>,
"Jonathan Corbet" <corbet@lwn.net>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Kees Cook" <kees@kernel.org>,
"Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org,
llvm@lists.linux.dev, linux-riscv@lists.infradead.org,
linux-arch@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-efi@vger.kernel.org,
rust-for-linux@vger.kernel.org, linux-doc@vger.kernel.org,
Jens Axboe <axboe@kernel.dk>,
linux-hardening@vger.kernel.org,
Petr Pavlu <petr.pavlu@suse.com>,
"Lorenzo Stoakes (ARM)" <ljs@kernel.org>
Subject: [PATCH v4 10/22] kbuild: implement and use depcheck to check dependency timestamps
Date: Wed, 23 Sep 2026 18:17:59 +0100 [thread overview]
Message-ID: <20260923-build-speedup-v4-10-73128809a4a4@kernel.org> (raw)
In-Reply-To: <20260923-build-speedup-v4-0-73128809a4a4@kernel.org>
Each object's .cmd file lists its header dependencies, which often
consists of over a thousand dependencies.
When little has changed in the tree, this is what make spends most of its
time doing, spending over a second, single-threaded when parsing larger
directory trees.
It performs considerably more work that is actually necessary to get the
job done.
This can be done faster in C, so implement scripts/basic/depcheck to do so.
It does as little work as possible, reading the .cmd files from a
directory's targets and running stat on each dependency only a single time.
It generates a fragment holding only the saved command line for a target
whose dependencies all exist and are older than it, and the entire .cmd
file for any other.
A dependency that is also a target of the same directory (e.g. header
generated by an if_changed rule) may get remade later in the same make run,
so do not treat a target as fresh.
That way, Makefile.build simply includes the fragment and the amount of
work make has to do is significantly reduced when there is not much work to
do.
If the operation fails, kbuild falls back to using .cmd files.
The result is exactly the same as before.
For drivers/gpu/drm/amd/amdgpu in an allmodconfig tree the fragment is a
fifth of the size of the .cmd files, make reads it in 10ms instead of
380ms, and the instance goes from 2.2s to 0.4s.
Whole build, 128-thread Threadripper 9980X, best of N runs:
before after delta
-------------------------------
x86 defconfig, no-op make, gcc 1.1s 0.78s -0.30s (-28%)
x86 defconfig, no-op make, clang 1.3s 0.94s -0.34s (-27%)
x86 allmodconfig, no-op make, gcc 14.5s 12.9s -1.6s (-11%)
x86 allmodconfig, no-op make, clang 15.5s 14.2s -1.3s (-9%)
x86 allmodconfig, touch mm/vma.c, gcc 34.3s 33.9s -0.33s (-1%)
x86 allmodconfig, touch mm/vma.c, clang 33.2s 32.2s -0.98s (-3%)
Assisted-by: LLM
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
Makefile | 1 +
scripts/Makefile.build | 15 +-
scripts/basic/.gitignore | 1 +
scripts/basic/Makefile | 2 +-
scripts/basic/depcheck.c | 481 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 498 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index ab3ba78376f7..554c9003a4d9 100644
--- a/Makefile
+++ b/Makefile
@@ -2241,6 +2241,7 @@ clean: $(clean-dirs)
$(call cmd,rmfiles)
@find . $(RCS_FIND_IGNORE) \
\( -name '*.[aios]' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \
+ -o -name '.depcheck.mk' -o -name '.depcheck.mk.tmp' \
-o -name '*.ko.*' -o -name '*.o.thinlto.bc' \
-o -name '*.dtb' -o -name '*.dtbo' \
-o -name '*.dtb.S' -o -name '*.dtbo.S' \
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 2cabfe85b798..819cc1f750e8 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -592,7 +592,20 @@ $(obj)/: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \
existing-targets := $(wildcard $(sort $(targets)))
--include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
+cmd-files := $(wildcard $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+# depcheck checks timestamps first and outputs only saved command lines of
+# up-to-date targets, falling back to .cmd files if it fails. A directory
+# whose targets all lie elsewhere may not exist in the output tree.
+depcheck := $(wildcard $(objtree)/scripts/basic/depcheck)
+
+ifneq ($(and $(depcheck),$(cmd-files),$(wildcard $(obj))),)
+ifeq ($(shell $(depcheck) $(obj)/.depcheck.mk $(cmd-files) && echo ok),ok)
+cmd-files := $(obj)/.depcheck.mk
+endif
+endif
+
+-include $(cmd-files)
# Create directories for object files if they do not exist
obj-dirs := $(sort $(patsubst %/,%, $(dir $(targets))))
diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore
index 07c195f605a1..761ee14f9477 100644
--- a/scripts/basic/.gitignore
+++ b/scripts/basic/.gitignore
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
+/depcheck
/fixdep
/randstruct.seed
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
index fb8e2c38fbc7..ff98780e474d 100644
--- a/scripts/basic/Makefile
+++ b/scripts/basic/Makefile
@@ -2,7 +2,7 @@
#
# fixdep: used to generate dependency information during build process
-hostprogs-always-y += fixdep
+hostprogs-always-y += fixdep depcheck
# randstruct: the seed is needed before building the gcc-plugin or
# before running a Clang kernel build.
diff --git a/scripts/basic/depcheck.c b/scripts/basic/depcheck.c
new file mode 100644
index 000000000000..119075353f3b
--- /dev/null
+++ b/scripts/basic/depcheck.c
@@ -0,0 +1,481 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * depcheck - check the dependency timestamps of a directory's targets so that
+ * make reads only what it needs from their .cmd files.
+ *
+ * fixdep writes a .cmd file as:
+ *
+ * savedcmd_dir/foo.o := <command line>
+ *
+ * source_dir/foo.o := dir/foo.c
+ *
+ * deps_dir/foo.o := \
+ * include/linux/bar.h \
+ * $(wildcard include/config/BAZ) \
+ *
+ * dir/foo.o: $(deps_dir/foo.o)
+ *
+ * $(deps_dir/foo.o):
+ *
+ * and kbuild may append rules of its own after that, such as one making the
+ * target depend on objtool.
+ *
+ * For a target that exists and is newer than every dependency listed, make can
+ * have nothing to do with the list, so it is left out and only what precedes
+ * and follows it is passed on; for anything else the .cmd file is passed on in
+ * full.
+ *
+ * Usage: depcheck <output> <.cmd files...>
+ *
+ * The output is a makefile fragment to include in place of the .cmd files; a
+ * non-zero exit status means the caller should include those instead.
+ */
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <hash.h>
+#include <hashtable.h>
+#include <xalloc.h>
+
+/* What fixdep writes, see above. */
+#define DEPS_PREFIX "deps_"
+#define DEPS_RULE_PREFIX "$(" DEPS_PREFIX
+#define RULE_SUFFIX ":"
+#define LINE_CONTINUATION " \\"
+#define WILDCARD_OPEN "$(wildcard "
+#define WILDCARD_CLOSE ")"
+#define CMD_SUFFIX ".cmd"
+
+/* A line of a .cmd file, without its newline. */
+struct line {
+ const char *text;
+ size_t len;
+};
+
+static bool is_blank(char chr)
+{
+ return chr == ' ' || chr == '\t';
+}
+
+static bool str_ends_with(const char *str, const char *suffix)
+{
+ const size_t len = strlen(str), suffix_len = strlen(suffix);
+
+ return len >= suffix_len && !strcmp(str + len - suffix_len, suffix);
+}
+
+static bool line_starts_with(const struct line *line, const char *prefix)
+{
+ const size_t len = strlen(prefix);
+
+ return line->len >= len && !memcmp(line->text, prefix, len);
+}
+
+static bool line_ends_with(const struct line *line, const char *suffix)
+{
+ const size_t len = strlen(suffix);
+
+ return line->len >= len &&
+ !memcmp(line->text + line->len - len, suffix, len);
+}
+
+static bool line_is_blank(const struct line *line)
+{
+ size_t i;
+
+ for (i = 0; i < line->len; i++)
+ if (!is_blank(line->text[i]))
+ return false;
+
+ return true;
+}
+
+/* Whether the line ends in " \", continuing the list on the next line. */
+static bool line_is_continued(const struct line *line)
+{
+ return line_ends_with(line, LINE_CONTINUATION);
+}
+
+static void line_strip_continuation(struct line *line)
+{
+ if (line_is_continued(line))
+ line->len -= strlen(LINE_CONTINUATION);
+}
+
+static void line_trim(struct line *line)
+{
+ while (line->len && is_blank(line->text[0])) {
+ line->text++;
+ line->len--;
+ }
+ while (line->len && is_blank(line->text[line->len - 1]))
+ line->len--;
+}
+
+/* Take the next line out of [*pos, end); false once there are none left. */
+static bool next_line(const char **pos, const char *end, struct line *line)
+{
+ const char *newline;
+
+ if (*pos >= end)
+ return false;
+
+ newline = memchr(*pos, '\n', end - *pos);
+ line->text = *pos;
+ line->len = (newline ? newline : end) - *pos;
+ *pos = newline ? newline + 1 : end;
+
+ return true;
+}
+
+/* Describes a dependency file. */
+struct dep {
+ struct hlist_node hnode;
+ struct timespec mtime;
+ bool exists;
+ char path[];
+};
+
+static HASHTABLE_DEFINE(dep_table, 1U << 16);
+
+/* The targets of this run's .cmd files: anything make may remake this time. */
+struct target {
+ struct hlist_node hnode;
+ char path[];
+};
+
+static HASHTABLE_DEFINE(target_table, 1U << 12);
+
+static void add_target(const char *path)
+{
+ struct target *target = xmalloc(sizeof(*target) + strlen(path) + 1);
+
+ strcpy(target->path, path);
+ hash_add(target_table, &target->hnode, hash_str(path));
+}
+
+static bool is_target(const char *path)
+{
+ const unsigned int key = hash_str(path);
+ struct target *target;
+
+ hash_for_each_possible(target_table, target, hnode, key) {
+ if (!strcmp(target->path, path))
+ return true;
+ }
+
+ return false;
+}
+
+static const struct dep *lookup_dep(const char *path)
+{
+ const unsigned int key = hash_str(path);
+ struct dep *dep;
+ struct stat st;
+
+ hash_for_each_possible(dep_table, dep, hnode, key) {
+ if (!strcmp(dep->path, path))
+ return dep;
+ }
+
+ dep = xcalloc(1, sizeof(*dep) + strlen(path) + 1);
+ strcpy(dep->path, path);
+ dep->exists = !stat(path, &st);
+ if (dep->exists)
+ dep->mtime = st.st_mtim;
+ hash_add(dep_table, &dep->hnode, key);
+
+ return dep;
+}
+
+/* Strictly newer, as make compares timestamps. */
+static bool newer(const struct timespec *time_a, const struct timespec *time_b)
+{
+ if (time_a->tv_sec != time_b->tv_sec)
+ return time_a->tv_sec > time_b->tv_sec;
+
+ return time_a->tv_nsec > time_b->tv_nsec;
+}
+
+/*
+ * $(wildcard include/config/FOO) is a prerequisite only while FOO is set:
+ * unwrap it and say that it is optional.
+ */
+static bool line_unwrap_wildcard(struct line *line)
+{
+ if (!line_starts_with(line, WILDCARD_OPEN) ||
+ !line_ends_with(line, WILDCARD_CLOSE))
+ return false;
+
+ line->text += strlen(WILDCARD_OPEN);
+ line->len -= strlen(WILDCARD_OPEN) + strlen(WILDCARD_CLOSE);
+
+ return true;
+}
+
+/* fixdep doubles '$' and escapes '#' in a path: undo that into path[]. */
+static bool unescape_path(const struct line *line, char *path, size_t size)
+{
+ size_t i, out_len = 0;
+
+ if (line->len >= size)
+ return false;
+
+ for (i = 0; i < line->len; i++) {
+ const char chr = line->text[i];
+ const char next_chr = i + 1 < line->len ? line->text[i + 1] : '\0';
+
+ if ((chr == '$' && next_chr == '$') || (chr == '\\' && next_chr == '#'))
+ i++;
+ path[out_len++] = line->text[i];
+ }
+ path[out_len] = '\0';
+
+ return true;
+}
+
+/* Is the path contained in line older than the target? */
+static bool dep_is_fresh(struct line line, const struct timespec *target)
+{
+ char path[PATH_MAX];
+ const struct dep *dep;
+ bool optional;
+
+ line_strip_continuation(&line);
+ line_trim(&line);
+ if (!line.len)
+ return false;
+
+ optional = line_unwrap_wildcard(&line);
+ if (!line.len || !unescape_path(&line, path, sizeof(path)))
+ return false;
+
+ /* A target can get 'remade' so its timestamp is meaningless. */
+ if (is_target(path))
+ return false;
+
+ dep = lookup_dep(path);
+ if (!dep->exists)
+ return optional;
+
+ return !newer(&dep->mtime, target);
+}
+
+/*
+ * Parse a dependency list which consists of one file per line and determine if
+ * all dependencies are 'fresh', i.e. older than the target.
+ */
+static bool deps_are_fresh(const char *pos, const char *end,
+ const struct timespec *target)
+{
+ struct line line;
+
+ while (next_line(&pos, end, &line)) {
+ if (line_is_blank(&line))
+ return true;
+ if (!dep_is_fresh(line, target))
+ return false;
+ if (!line_is_continued(&line))
+ return true;
+ }
+
+ return true;
+}
+
+/*
+ * Find the "deps_" line in the input.
+ *
+ * On success returns true and *deps_off is set to its offset and *list is set
+ * to the list's own lines start or NULL if the line is not continued.
+ *
+ * Otherwise returns false if the prefix cannot be found.
+ */
+static bool find_deps(const char *buf, size_t len, size_t *deps_off,
+ const char **list)
+{
+ const char *pos = buf, *end = buf + len;
+ struct line line;
+
+ while (next_line(&pos, end, &line)) {
+ if (!line_starts_with(&line, DEPS_PREFIX))
+ continue;
+
+ *deps_off = line.text - buf;
+ *list = line_is_continued(&line) ? pos : NULL;
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Is this the target of a .cmd file, i.e. 'dir/.name.cmd names dir/name.'?
+ */
+static bool target_of(const char *cmd_path, char *target, size_t size)
+{
+ const char *slash = strrchr(cmd_path, '/');
+ const char *base = slash ? slash + 1 : cmd_path;
+ const size_t dir_len = base - cmd_path;
+ const size_t affix_len = strlen(".") + strlen(CMD_SUFFIX);
+ const size_t base_len = strlen(base);
+
+ if (base[0] != '.' || !str_ends_with(base, CMD_SUFFIX) ||
+ base_len <= affix_len)
+ return false;
+
+ return snprintf(target, size, "%.*s%.*s", (int)dir_len, cmd_path,
+ (int)(base_len - affix_len), base + 1) < (int)size;
+}
+
+/*
+ * Does the .cmd file's target exists and is it newer than everything in its
+ * dependency list?
+ *
+ * Returns true if so and sets *deps_off to the start of the list, otherwise
+ * returns false.
+ */
+static bool target_is_fresh(const char *cmd_path, const char *buf, size_t len,
+ size_t *deps_off)
+{
+ char target[PATH_MAX];
+ struct stat st;
+ const char *list;
+
+ if (!target_of(cmd_path, target, sizeof(target)) || stat(target, &st))
+ return false;
+ if (!find_deps(buf, len, deps_off, &list))
+ return false;
+ if (!list)
+ return true;
+
+ return deps_are_fresh(list, buf + len, &st.st_mtim);
+}
+
+static char *read_file(const char *path, size_t *len)
+{
+ FILE *file = fopen(path, "r");
+ struct stat st;
+ char *buf;
+ size_t nr_read = 0;
+
+ if (!file)
+ return NULL;
+ if (fstat(fileno(file), &st)) {
+ fclose(file);
+ return NULL;
+ }
+
+ buf = xmalloc(st.st_size + 1);
+ while (nr_read < (size_t)st.st_size) {
+ const size_t chunk = fread(buf + nr_read, 1, st.st_size - nr_read, file);
+
+ if (!chunk)
+ break;
+ nr_read += chunk;
+ }
+ fclose(file);
+
+ buf[nr_read] = '\0';
+ *len = nr_read;
+ return buf;
+}
+
+/*
+ * Find the end of the dependency block: the offset just past its closing
+ * "$(deps_x):" line. Anything after that was appended by kbuild and is not for
+ * us to judge. Returns len if the line cannot be found.
+ */
+static size_t deps_block_end(const char *buf, size_t len, size_t deps_off)
+{
+ const char *pos = buf + deps_off, *end = buf + len;
+ struct line line;
+
+ while (next_line(&pos, end, &line)) {
+ if (line_starts_with(&line, DEPS_RULE_PREFIX) &&
+ line_ends_with(&line, RULE_SUFFIX))
+ return pos - buf;
+ }
+
+ return len;
+}
+
+/* The target is fresh: pass on everything but the dependency block. */
+static void write_without_deps(FILE *out, const char *buf, size_t len,
+ size_t deps_off)
+{
+ const size_t tail_off = deps_block_end(buf, len, deps_off);
+
+ fwrite(buf, 1, deps_off, out);
+ fputc('\n', out);
+ fwrite(buf + tail_off, 1, len - tail_off, out);
+}
+
+/*
+ * Generate a fragment for make from one .cmd file - without the dependency
+ * block if the target is fresh, otherwise all of it.
+ */
+static void process(FILE *out, const char *cmd_path)
+{
+ size_t len, deps_off;
+ char *buf;
+
+ buf = read_file(cmd_path, &len);
+ if (!buf)
+ return;
+
+ if (target_is_fresh(cmd_path, buf, len, &deps_off))
+ write_without_deps(out, buf, len, deps_off);
+ else
+ fwrite(buf, 1, len, out);
+
+ free(buf);
+}
+
+int main(int argc, char **argv)
+{
+ char tmp_path[PATH_MAX];
+ FILE *out;
+ int i;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <output> <.cmd files...>\n", argv[0]);
+ return 1;
+ }
+
+ if (snprintf(tmp_path, sizeof(tmp_path), "%s.tmp", argv[1]) >=
+ (int)sizeof(tmp_path)) {
+ fprintf(stderr, "%s: path too long\n", argv[1]);
+ return 1;
+ }
+
+ out = fopen(tmp_path, "w");
+ if (!out) {
+ perror(tmp_path);
+ return 1;
+ }
+
+ for (i = 2; i < argc; i++) {
+ char target[PATH_MAX];
+
+ if (target_of(argv[i], target, sizeof(target)))
+ add_target(target);
+ }
+
+ for (i = 2; i < argc; i++)
+ process(out, argv[i]);
+
+ /* Write errors are latched in the stream, so one check at the end covers them all. */
+ if (ferror(out) || fclose(out) || rename(tmp_path, argv[1])) {
+ perror(argv[1]);
+ unlink(tmp_path);
+ return 1;
+ }
+
+ return 0;
+}
--
2.55.0
next prev parent reply other threads:[~2026-09-23 17:20 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-23 17:17 [PATCH v4 00/22] kbuild: significantly speed up kernel builds Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 01/22] kbuild: do not allocate .modinfo in vmlinux Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 02/22] kallsyms: index symbols by token to speed up table compression Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 03/22] kallsyms: output binary data to speed output and kallsyms assembly Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 04/22] sorttable: parse nm output correctly Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 05/22] kbuild: do not sort nm output where the order is irrelevant Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 06/22] kbuild: only emit vmlinux relocations when required Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 07/22] elf-parse: add section flags, symbol binding and mapping helpers Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 08/22] kallsyms: reimplement mksysmap in C Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` [PATCH v4 09/22] kbuild: calculate list, composite object state per object Lorenzo Stoakes (ARM)
2026-09-23 17:17 ` Lorenzo Stoakes (ARM) [this message]
2026-09-23 17:18 ` [PATCH v4 11/22] kbuild: move the toolchain checks into scripts/Kconfig.toolchain Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 12/22] kbuild: avoid re-running compiler and linker probes Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 13/22] modpost: cache section relocation mismatch state Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 14/22] modpost: emit module descriptors as assembly Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 15/22] kbuild: batch module finalisation Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 16/22] objtool: do not hash DWARF relocations Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 17/22] objtool: cache relocations, do less work, eliminate relocation hash Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 18/22] objtool: size the instruction hash to the text Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 19/22] objtool: decode instructions and resolve branch targets in parallel Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 20/22] rust: make exports.o depend on the headers generated for it Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 21/22] kbuild: build rust crates in parallel with the rest of the build Lorenzo Stoakes (ARM)
2026-09-23 17:18 ` [PATCH v4 22/22] kbuild: compress the kernel with pigz if available Lorenzo Stoakes (ARM)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260923-build-speedup-v4-10-73128809a4a4@kernel.org \
--to=ljs@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=alex@ghiti.fr \
--cc=aliceryhl@google.com \
--cc=aou@eecs.berkeley.edu \
--cc=ardb@kernel.org \
--cc=arnd@arndb.de \
--cc=axboe@kernel.dk \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=bp@alien8.de \
--cc=catalin.marinas@arm.com \
--cc=corbet@lwn.net \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dave.hansen@linux.intel.com \
--cc=gary@garyguo.net \
--cc=gustavoars@kernel.org \
--cc=hpa@zytor.com \
--cc=ilias.apalodimas@linaro.org \
--cc=jpoimboe@kernel.org \
--cc=justinstitt@google.com \
--cc=kees@kernel.org \
--cc=legion@kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=llvm@lists.linux.dev \
--cc=lossin@kernel.org \
--cc=mark.rutland@arm.com \
--cc=masahiroy@kernel.org \
--cc=mingo@redhat.com \
--cc=morbo@google.com \
--cc=nathan@kernel.org \
--cc=ndesaulniers@google.com \
--cc=nsc@kernel.org \
--cc=ojeda@kernel.org \
--cc=palmer@dabbelt.com \
--cc=peterz@infradead.org \
--cc=petr.pavlu@suse.com \
--cc=pjw@kernel.org \
--cc=rdunlap@infradead.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tamird@kernel.org \
--cc=tglx@kernel.org \
--cc=tmgross@umich.edu \
--cc=torvalds@linux-foundation.org \
--cc=will@kernel.org \
--cc=work@onurozkan.dev \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®