Skip to content

Commit 4b76998

Browse files
committed
Merge branch 'ab/coccicheck-incremental'
"make coccicheck" is time consuming. It has been made to run more incrementally. * ab/coccicheck-incremental: Makefile: don't create a ".build/.build/" for cocci, fix output spatchcache: add a ccache-alike for "spatch" cocci: run against a generated ALL.cocci cocci rules: remove <id>'s from rules that don't need them Makefile: copy contrib/coccinelle/*.cocci to build/ cocci: optimistically use COMPUTE_HEADER_DEPENDENCIES cocci: make "coccicheck" rule incremental cocci: split off "--all-includes" from SPATCH_FLAGS cocci: split off include-less "tests" from SPATCH_FLAGS Makefile: split off SPATCH_BATCH_SIZE comment from "cocci" heading Makefile: have "coccicheck" re-run if flags change Makefile: add ability to TAB-complete cocci *.patch rules cocci rules: remove unused "F" metavariable from pending rule Makefile + shared.mak: rename and indent $(QUIET_SPATCH_T)
2 parents 613fb30 + 0d12792 commit 4b76998

File tree

11 files changed

+515
-33
lines changed

11 files changed

+515
-33
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
/GIT-PERL-HEADER
99
/GIT-PYTHON-VARS
1010
/GIT-SCRIPT-DEFINES
11+
/GIT-SPATCH-DEFINES
1112
/GIT-USER-AGENT
1213
/GIT-VERSION-FILE
1314
/bin-wrappers/

Makefile

Lines changed: 150 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,11 +1367,53 @@ SP_EXTRA_FLAGS = -Wno-universal-initializer
13671367
SANITIZE_LEAK =
13681368
SANITIZE_ADDRESS =
13691369

1370-
# For the 'coccicheck' target; setting SPATCH_BATCH_SIZE higher will
1371-
# usually result in less CPU usage at the cost of higher peak memory.
1372-
# Setting it to 0 will feed all files in a single spatch invocation.
1373-
SPATCH_FLAGS = --all-includes
1374-
SPATCH_BATCH_SIZE = 1
1370+
# For the 'coccicheck' target
1371+
SPATCH_INCLUDE_FLAGS = --all-includes
1372+
SPATCH_FLAGS =
1373+
SPATCH_TEST_FLAGS =
1374+
1375+
# If *.o files are present, have "coccicheck" depend on them, with
1376+
# COMPUTE_HEADER_DEPENDENCIES this will speed up the common-case of
1377+
# only needing to re-generate coccicheck results for the users of a
1378+
# given API if it's changed, and not all files in the project. If
1379+
# COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.
1380+
SPATCH_USE_O_DEPENDENCIES = YesPlease
1381+
1382+
# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci
1383+
# files into a single contrib/cocci/ALL.cocci before running
1384+
# "coccicheck".
1385+
#
1386+
# Pros:
1387+
#
1388+
# - Speeds up a one-shot run of "make coccicheck", as we won't have to
1389+
# parse *.[ch] files N times for the N *.cocci rules
1390+
#
1391+
# Cons:
1392+
#
1393+
# - Will make incremental development of *.cocci slower, as
1394+
# e.g. changing strbuf.cocci will re-run all *.cocci.
1395+
#
1396+
# - Makes error and performance analysis harder, as rules will be
1397+
# applied from a monolithic ALL.cocci, rather than
1398+
# e.g. strbuf.cocci. To work around this either undefine this, or
1399+
# generate a specific patch, e.g. this will always use strbuf.cocci,
1400+
# not ALL.cocci:
1401+
#
1402+
# make contrib/coccinelle/strbuf.cocci.patch
1403+
SPATCH_CONCAT_COCCI = YesPlease
1404+
1405+
# Rebuild 'coccicheck' if $(SPATCH), its flags etc. change
1406+
TRACK_SPATCH_DEFINES =
1407+
TRACK_SPATCH_DEFINES += $(SPATCH)
1408+
TRACK_SPATCH_DEFINES += $(SPATCH_INCLUDE_FLAGS)
1409+
TRACK_SPATCH_DEFINES += $(SPATCH_FLAGS)
1410+
TRACK_SPATCH_DEFINES += $(SPATCH_TEST_FLAGS)
1411+
GIT-SPATCH-DEFINES: FORCE
1412+
@FLAGS='$(TRACK_SPATCH_DEFINES)'; \
1413+
if test x"$$FLAGS" != x"`cat GIT-SPATCH-DEFINES 2>/dev/null`" ; then \
1414+
echo >&2 " * new spatch flags"; \
1415+
echo "$$FLAGS" >GIT-SPATCH-DEFINES; \
1416+
fi
13751417

13761418
include config.mak.uname
13771419
-include config.mak.autogen
@@ -3207,35 +3249,113 @@ check: $(GENERATED_H)
32073249
exit 1; \
32083250
fi
32093251

3252+
COCCI_GEN_ALL = .build/contrib/coccinelle/ALL.cocci
3253+
COCCI_GLOB = $(wildcard contrib/coccinelle/*.cocci)
3254+
COCCI_RULES_TRACKED = $(COCCI_GLOB:%=.build/%)
3255+
COCCI_RULES_TRACKED_NO_PENDING = $(filter-out %.pending.cocci,$(COCCI_RULES_TRACKED))
3256+
COCCI_RULES =
3257+
COCCI_RULES += $(COCCI_GEN_ALL)
3258+
COCCI_RULES += $(COCCI_RULES_TRACKED)
3259+
COCCI_NAMES =
3260+
COCCI_NAMES += $(COCCI_RULES:.build/contrib/coccinelle/%.cocci=%)
3261+
3262+
COCCICHECK_PENDING = $(filter %.pending.cocci,$(COCCI_RULES))
3263+
COCCICHECK = $(filter-out $(COCCICHECK_PENDING),$(COCCI_RULES))
3264+
3265+
COCCICHECK_PATCHES = $(COCCICHECK:%=%.patch)
3266+
COCCICHECK_PATCHES_PENDING = $(COCCICHECK_PENDING:%=%.patch)
3267+
3268+
COCCICHECK_PATCHES_INTREE = $(COCCICHECK_PATCHES:.build/%=%)
3269+
COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)
3270+
3271+
# It's expensive to compute the many=many rules below, only eval them
3272+
# on $(MAKECMDGOALS) that match these $(COCCI_RULES)
3273+
COCCI_RULES_GLOB =
3274+
COCCI_RULES_GLOB += cocci%
3275+
COCCI_RULES_GLOB += .build/contrib/coccinelle/%
3276+
COCCI_RULES_GLOB += $(COCCICHECK_PATCHES)
3277+
COCCI_RULES_GLOB += $(COCCICHEC_PATCHES_PENDING)
3278+
COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_INTREE)
3279+
COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_PENDING_INTREE)
3280+
COCCI_GOALS = $(filter $(COCCI_RULES_GLOB),$(MAKECMDGOALS))
3281+
32103282
COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)
32113283

3212-
%.cocci.patch: %.cocci $(COCCI_SOURCES)
3213-
$(QUIET_SPATCH) \
3214-
if test $(SPATCH_BATCH_SIZE) = 0; then \
3215-
limit=; \
3216-
else \
3217-
limit='-n $(SPATCH_BATCH_SIZE)'; \
3218-
fi; \
3219-
if ! echo $(COCCI_SOURCES) | xargs $$limit \
3220-
$(SPATCH) $(SPATCH_FLAGS) \
3221-
--sp-file $< --patch . \
3222-
>$@+ 2>$@.log; \
3284+
$(COCCI_RULES_TRACKED): .build/% : %
3285+
$(call mkdir_p_parent_template)
3286+
$(QUIET_CP)cp $< $@
3287+
3288+
.build/contrib/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)
3289+
$(call mkdir_p_parent_template)
3290+
$(QUIET_GEN) >$@
3291+
3292+
$(COCCI_GEN_ALL): $(COCCI_RULES_TRACKED_NO_PENDING)
3293+
$(call mkdir_p_parent_template)
3294+
$(QUIET_SPATCH_CAT)cat $^ >$@
3295+
3296+
ifeq ($(COMPUTE_HEADER_DEPENDENCIES),no)
3297+
SPATCH_USE_O_DEPENDENCIES =
3298+
endif
3299+
define cocci-rule
3300+
3301+
## Rule for .build/$(1).patch/$(2); Params:
3302+
# $(1) = e.g. ".build/contrib/coccinelle/free.cocci"
3303+
# $(2) = e.g. "grep.c"
3304+
# $(3) = e.g. "grep.o"
3305+
COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch
3306+
$(1).d/$(2).patch: GIT-SPATCH-DEFINES
3307+
$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)
3308+
$(1).d/$(2).patch: $(1)
3309+
$(1).d/$(2).patch: $(1).d/%.patch : %
3310+
$$(call mkdir_p_parent_template)
3311+
$$(QUIET_SPATCH)if ! $$(SPATCH) $$(SPATCH_FLAGS) \
3312+
$$(SPATCH_INCLUDE_FLAGS) \
3313+
--sp-file $(1) --patch . $$< \
3314+
>$$@ 2>$$@.log; \
32233315
then \
3224-
cat $@.log; \
3316+
echo "ERROR when applying '$(1)' to '$$<'; '$$@.log' follows:"; \
3317+
cat $$@.log; \
32253318
exit 1; \
3226-
fi; \
3227-
mv $@+ $@; \
3228-
if test -s $@; \
3319+
fi
3320+
endef
3321+
3322+
define cocci-matrix
3323+
3324+
$(foreach s,$(COCCI_SOURCES),$(call cocci-rule,$(c),$(s),$(s:%.c=%.o)))
3325+
endef
3326+
3327+
ifdef COCCI_GOALS
3328+
$(eval $(foreach c,$(COCCI_RULES),$(call cocci-matrix,$(c))))
3329+
endif
3330+
3331+
define spatch-rule
3332+
3333+
.build/contrib/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))
3334+
$$(QUIET_SPATCH_CAT)cat $$^ >$$@ && \
3335+
if test -s $$@; \
32293336
then \
3230-
echo ' ' SPATCH result: $@; \
3337+
echo ' ' SPATCH result: $$@; \
32313338
fi
3339+
contrib/coccinelle/$(1).cocci.patch: .build/contrib/coccinelle/$(1).cocci.patch
3340+
$$(QUIET_CP)cp $$< $$@
3341+
3342+
endef
3343+
3344+
ifdef COCCI_GOALS
3345+
$(eval $(foreach n,$(COCCI_NAMES),$(call spatch-rule,$(n))))
3346+
endif
32323347

32333348
COCCI_TEST_RES_GEN = $(addprefix .build/,$(COCCI_TEST_RES))
3349+
$(COCCI_TEST_RES_GEN): GIT-SPATCH-DEFINES
32343350
$(COCCI_TEST_RES_GEN): .build/%.res : %.c
32353351
$(COCCI_TEST_RES_GEN): .build/%.res : %.res
3352+
ifdef SPATCH_CONCAT_COCCI
3353+
$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : $(COCCI_GEN_ALL)
3354+
else
32363355
$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci
3356+
endif
32373357
$(call mkdir_p_parent_template)
3238-
$(QUIET_SPATCH_T)$(SPATCH) $(SPATCH_FLAGS) \
3358+
$(QUIET_SPATCH_TEST)$(SPATCH) $(SPATCH_TEST_FLAGS) \
32393359
--very-quiet --no-show-diff \
32403360
--sp-file $< -o $@ \
32413361
$(@:.build/%.res=%.c) && \
@@ -3246,11 +3366,15 @@ $(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinell
32463366
coccicheck-test: $(COCCI_TEST_RES_GEN)
32473367

32483368
coccicheck: coccicheck-test
3249-
coccicheck: $(addsuffix .patch,$(filter-out %.pending.cocci,$(wildcard contrib/coccinelle/*.cocci)))
3369+
ifdef SPATCH_CONCAT_COCCI
3370+
coccicheck: contrib/coccinelle/ALL.cocci.patch
3371+
else
3372+
coccicheck: $(COCCICHECK_PATCHES_INTREE)
3373+
endif
32503374

32513375
# See contrib/coccinelle/README
32523376
coccicheck-pending: coccicheck-test
3253-
coccicheck-pending: $(addsuffix .patch,$(wildcard contrib/coccinelle/*.pending.cocci))
3377+
coccicheck-pending: $(COCCICHECK_PATCHES_PENDING_INTREE)
32543378

32553379
.PHONY: coccicheck coccicheck-pending
32563380

@@ -3517,8 +3641,9 @@ profile-clean:
35173641
$(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
35183642

35193643
cocciclean:
3644+
$(RM) GIT-SPATCH-DEFINES
35203645
$(RM) -r .build/contrib/coccinelle
3521-
$(RM) contrib/coccinelle/*.cocci.patch*
3646+
$(RM) contrib/coccinelle/*.cocci.patch
35223647

35233648
clean: profile-clean coverage-clean cocciclean
35243649
$(RM) -r .build

contrib/coccinelle/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
*.patch*
1+
*.patch

contrib/coccinelle/README

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,52 @@ There are two types of semantic patches:
4141

4242
This allows to expose plans of pending large scale refactorings without
4343
impacting the bad pattern checks.
44+
45+
Git-specific tips & things to know about how we run "spatch":
46+
47+
* The "make coccicheck" will piggy-back on
48+
"COMPUTE_HEADER_DEPENDENCIES". If you've built a given object file
49+
the "coccicheck" target will consider its depednency to decide if
50+
it needs to re-run on the corresponding source file.
51+
52+
This means that a "make coccicheck" will re-compile object files
53+
before running. This might be unexpected, but speeds up the run in
54+
the common case, as e.g. a change to "column.h" won't require all
55+
coccinelle rules to be re-run against "grep.c" (or another file
56+
that happens not to use "column.h").
57+
58+
To disable this behavior use the "SPATCH_USE_O_DEPENDENCIES=NoThanks"
59+
flag.
60+
61+
* To speed up our rules the "make coccicheck" target will by default
62+
concatenate all of the *.cocci files here into an "ALL.cocci", and
63+
apply it to each source file.
64+
65+
This makes the run faster, as we don't need to run each rule
66+
against each source file. See the Makefile for further discussion,
67+
this behavior can be disabled with "SPATCH_CONCAT_COCCI=".
68+
69+
But since they're concatenated any <id> in the <rulname> (e.g. "@
70+
my_name", v.s. anonymous "@@") needs to be unique across all our
71+
*.cocci files. You should only need to name rules if other rules
72+
depend on them (currently only one rule is named).
73+
74+
* To speed up incremental runs even more use the "spatchcache" tool
75+
in this directory as your "SPATCH". It aimns to be a "ccache" for
76+
coccinelle, and piggy-backs on "COMPUTE_HEADER_DEPENDENCIES".
77+
78+
It caches in Redis by default, see it source for a how-to.
79+
80+
In one setup with a primed cache "make coccicheck" followed by a
81+
"make clean && make" takes around 10s to run, but 2m30s with the
82+
default of "SPATCH_CONCAT_COCCI=Y".
83+
84+
With "SPATCH_CONCAT_COCCI=" the total runtime is around ~6m, sped
85+
up to ~1m with "spatchcache".
86+
87+
Most of the 10s (or ~1m) being spent on re-running "spatch" on
88+
files we couldn't cache, as we didn't compile them (in contrib/*
89+
and compat/* mostly).
90+
91+
The absolute times will differ for you, but the relative speedup
92+
from caching should be on that order.

contrib/coccinelle/hashmap.cocci

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@ hashmap_entry_init_usage @
1+
@@
22
expression E;
33
struct hashmap_entry HME;
44
@@

contrib/coccinelle/preincr.cocci

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@ preincrement @
1+
@@
22
identifier i;
33
@@
44
- ++i > 1

0 commit comments

Comments
 (0)