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>
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>,
"Lorenzo Stoakes (ARM)" <ljs@kernel.org>
Subject: [PATCH 11/23] kbuild: implement and use depcheck to check dependency timestamps
Date: Tue, 08 Sep 2026 21:55:11 +0100 [thread overview]
Message-ID: <20260908-build-speedup-v1-11-5dc1ac01672d@kernel.org> (raw)
In-Reply-To: <20260908-build-speedup-v1-0-5dc1ac01672d@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.
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 0.92s 0.62s -0.29s (-32%)
x86 defconfig, no-op make, clang 1.1s 0.78s -0.31s (-29%)
x86 allmodconfig, no-op make, gcc 12.3s 11.2s -1.2s (-10%)
x86 allmodconfig, no-op make, clang 13.2s 11.9s -1.3s (-10%)
x86 allmodconfig, touch mm/vma.c, gcc 40.9s 40.6s -0.3s (-1%)
x86 allmodconfig, touch mm/vma.c, clang 37.6s 36.5s -1.0s (-3%)
Assisted-by: LLM
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
Makefile | 1 +
scripts/Makefile.build | 14 +-
scripts/basic/.gitignore | 1 +
scripts/basic/Makefile | 2 +-
scripts/basic/depcheck.c | 442 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 458 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index 85eb2fd026cb..56e56bea53c3 100644
--- a/Makefile
+++ b/Makefile
@@ -2239,6 +2239,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..b9093b39cc2f 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -592,7 +592,19 @@ $(obj)/: $(if $(KBUILD_BUILTIN), $(targets-for-builtin)) \
existing-targets := $(wildcard $(sort $(targets)))
--include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
+cmd-files := $(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.
+depcheck := $(wildcard $(objtree)/scripts/basic/depcheck)
+
+ifneq ($(and $(depcheck),$(cmd-files)),)
+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..5f9bbdff8803
--- /dev/null
+++ b/scripts/basic/depcheck.c
@@ -0,0 +1,442 @@
+// 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);
+
+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 = xmalloc(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;
+
+ 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;
+ size_t name_len;
+
+ if (base[0] != '.' || !str_ends_with(base, CMD_SUFFIX))
+ return false;
+
+ name_len = strlen(base) - strlen(".") - strlen(CMD_SUFFIX);
+ if (!name_len)
+ return false;
+
+ return snprintf(target, size, "%.*s%.*s", (int)dir_len, cmd_path,
+ (int)name_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++)
+ process(out, argv[i]);
+
+ if (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-08 20:57 UTC|newest]
Thread overview: 91+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-08 20:55 [PATCH 00/23] kbuild: significantly speed up kernel builds Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 01/23] scripts/mksysmap: drop the MODULE_INFO() symbols from kallsyms Lorenzo Stoakes (ARM)
2026-09-09 19:47 ` Nicolas Schier
2026-09-10 11:00 ` Lorenzo Stoakes (ARM)
2026-09-10 4:19 ` Nathan Chancellor
2026-09-10 11:03 ` Lorenzo Stoakes (ARM)
2026-09-10 19:00 ` Nicolas Schier
2026-09-08 20:55 ` [PATCH 02/23] scripts/mksysmap: fix escape of '$' in the __pi_ pattern Lorenzo Stoakes (ARM)
2026-09-09 19:47 ` Nicolas Schier
2026-09-10 11:04 ` Lorenzo Stoakes (ARM)
2026-09-10 4:19 ` Nathan Chancellor
2026-09-10 11:21 ` Lorenzo Stoakes (ARM)
2026-09-10 19:00 ` Nicolas Schier
2026-09-08 20:55 ` [PATCH 03/23] kallsyms: index symbols by token to speed up table compression Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 04/23] kallsyms: output binary data to speed output and kallsyms assembly Lorenzo Stoakes (ARM)
2026-09-09 14:35 ` Linus Torvalds
2026-09-10 9:29 ` David Laight
2026-09-11 11:07 ` Lorenzo Stoakes (ARM)
2026-09-12 6:38 ` [4/23] " Markus Elfring
2026-09-08 20:55 ` [PATCH 05/23] kbuild: do not sort nm output where the order is irrelevant Lorenzo Stoakes (ARM)
2026-09-10 4:19 ` Nathan Chancellor
2026-09-08 20:55 ` [PATCH 06/23] kbuild: only emit vmlinux relocations when required Lorenzo Stoakes (ARM)
2026-09-10 4:19 ` Nathan Chancellor
2026-09-08 20:55 ` [PATCH 07/23] elf-parse: add section flags, symbol binding and a read-only mapping Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 08/23] kallsyms: reimplement mksysmap in C Lorenzo Stoakes (ARM)
2026-09-11 18:52 ` Markus Elfring
2026-09-11 19:15 ` Markus Elfring
2026-09-11 19:42 ` Markus Elfring
2026-09-08 20:55 ` [PATCH 09/23] kbuild: do not allocate .modinfo in vmlinux Lorenzo Stoakes (ARM)
2026-09-10 4:19 ` Nathan Chancellor
2026-09-10 10:59 ` Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 10/23] kbuild: cache list, composite object state per object Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` Lorenzo Stoakes (ARM) [this message]
2026-09-09 15:26 ` [PATCH 11/23] kbuild: implement and use depcheck to check dependency timestamps Linus Torvalds
2026-09-08 20:55 ` [PATCH 12/23] kbuild: avoid re-running compiler and linker probes Lorenzo Stoakes (ARM)
2026-09-10 4:19 ` Nathan Chancellor
2026-09-10 15:42 ` Nicolas Schier
2026-09-11 10:30 ` Lorenzo Stoakes (ARM)
2026-09-11 18:10 ` Nicolas Schier
2026-09-11 18:25 ` Lorenzo Stoakes (ARM)
2026-09-11 17:33 ` David Laight
2026-09-11 18:17 ` Nicolas Schier
2026-09-11 18:24 ` Lorenzo Stoakes (ARM)
2026-09-11 19:34 ` Nicolas Schier
2026-09-11 21:01 ` David Laight
2026-09-12 7:11 ` Nathan Chancellor
2026-09-11 10:26 ` Lorenzo Stoakes (ARM)
2026-09-12 6:51 ` Nathan Chancellor
2026-09-12 10:03 ` David Laight
2026-09-08 20:55 ` [PATCH 13/23] modpost: hash module source per-file, not per-byte Lorenzo Stoakes (ARM)
2026-09-10 12:52 ` Petr Pavlu
2026-09-11 10:41 ` Lorenzo Stoakes (ARM)
2026-09-11 11:57 ` Petr Pavlu
2026-09-11 12:21 ` Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 14/23] modpost: cache section relocation mismatch state Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 15/23] modpost: emit module descriptors as assembly Lorenzo Stoakes (ARM)
2026-09-09 14:59 ` Linus Torvalds
2026-09-08 20:55 ` [PATCH 16/23] kbuild: batch module finalisation Lorenzo Stoakes (ARM)
2026-09-10 15:48 ` Nicolas Schier
2026-09-11 10:23 ` Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 17/23] modpost: perform srcversion hashing in parallel Lorenzo Stoakes (ARM)
2026-09-10 10:32 ` David Laight
2026-09-11 10:49 ` Lorenzo Stoakes (ARM)
2026-09-12 11:50 ` Yann Droneaud
2026-09-08 20:55 ` [PATCH 18/23] objtool: cache relocations and function dead end state, do less work Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 19/23] objtool: decode instructions and resolve branch targets in parallel Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 20/23] kbuild: rust: parallelise rustc front end Lorenzo Stoakes (ARM)
2026-09-08 21:13 ` Miguel Ojeda
2026-09-09 14:22 ` Lorenzo Stoakes (ARM)
2026-09-09 10:22 ` Björn Baron
2026-09-09 12:59 ` Miguel Ojeda
2026-09-09 14:26 ` Lorenzo Stoakes (ARM)
2026-09-10 12:25 ` Nicolas Schier (FRITZ!)
2026-09-11 19:00 ` Nicolas Schier
2026-09-08 20:55 ` [PATCH 21/23] rust: make exports.o depend on the headers generated for it Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 22/23] kbuild: build rust crates in parallel with the rest of the build Lorenzo Stoakes (ARM)
2026-09-08 20:55 ` [PATCH 23/23] kbuild: use pigz for gzip compression if available Lorenzo Stoakes (ARM)
2026-09-10 4:19 ` Nathan Chancellor
2026-09-11 11:03 ` Lorenzo Stoakes (ARM)
2026-09-12 6:38 ` Nathan Chancellor
2026-09-08 21:06 ` [PATCH 00/23] kbuild: significantly speed up kernel builds Nick Desaulniers
2026-09-09 14:17 ` Lorenzo Stoakes (ARM)
2026-09-09 22:09 ` Nick Desaulniers
2026-09-11 11:25 ` Lorenzo Stoakes (ARM)
2026-09-09 15:37 ` Linus Torvalds
2026-09-09 16:30 ` Lorenzo Stoakes (ARM)
2026-09-09 21:58 ` Florian Fainelli
2026-09-11 11:28 ` Lorenzo Stoakes (ARM)
2026-09-12 6:44 ` Nathan Chancellor
2026-09-10 4:19 ` Nathan Chancellor
2026-09-11 11:13 ` 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=20260908-build-speedup-v1-11-5dc1ac01672d@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=hpa@zytor.com \
--cc=ilias.apalodimas@linaro.org \
--cc=jpoimboe@kernel.org \
--cc=justinstitt@google.com \
--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-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=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