Skip to content

Commit 36a1b00

Browse files
captain5050acmel
authored andcommitted
perf build: Reduce pmu-events related copying and mkdirs
When building to an output directory the previous code would remove files and then copy the source files over. Each source file copy would have a rule to make its directory. All JSON for every architecture was considered a source file. This led to unnecessary copying as a file would be deleted and then the same file copied again, unnecessary directory making, and copying of files not used in the build. A side-effect would be a lot of build messages. This change makes it so that all computed output files are created and then compared to all files in the OUTPUT directory. By filtering out the files that would be copied, unnecessary files can be determined and then deleted - note, this is a phony target which would remake the pmu-events.c if always depended upon, and so the dependency is conditional on there being files to remove. This has some overhead as the $(OUTPUT)/pmu-events is "find" over rather than just "rm -fr", but the savings from unnecessary copying, etc. should make up for this new make overhead. The copy target just does copying but has a dependency on the directory it needs being built, avoiding repetitive mkdirs. The source files for copying only consider the JEVENTS_ARCH unless the JEVENTS_ARCH is all. The metric JSON is only generated if appropriate, rather than always being generated and jevents.py deciding whether or not to use the files. The mypy and pylint targets are fixed as variable names had changed but the rules not updated. The line count of a build with "make -C tools/perf O=/tmp/perf clean all" prior to this change was 2181 lines, after this change it is 1596 lines. This is a reduction of 585 lines or about 27%. The generated pmu-events.c for JEVENTS_ARCH "x86" and "all" were validated as being identical after this change. Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Leo Yan <leo.yan@arm.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 4479884 commit 36a1b00

1 file changed

Lines changed: 149 additions & 68 deletions

File tree

  • tools/perf/pmu-events

tools/perf/pmu-events/Build

Lines changed: 149 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,61 @@
1-
pmu-events-y += pmu-events.o
2-
JSON = $(shell find pmu-events/arch -name '*.json' -o -name '*.csv')
3-
JSON_DIRS = $(shell find pmu-events/arch -type d)
4-
JDIR_TEST = pmu-events/arch/test
5-
JSON_TEST = $(shell [ -d $(JDIR_TEST) ] && \
6-
find $(JDIR_TEST) -name '*.json')
7-
JEVENTS_PY = pmu-events/jevents.py
8-
METRIC_PY = pmu-events/metric.py
9-
METRIC_TEST_PY = pmu-events/metric_test.py
101
EMPTY_PMU_EVENTS_C = pmu-events/empty-pmu-events.c
2+
# pmu-events.c will be generated by jevents.py or copied from EMPTY_PMU_EVENTS_C
113
PMU_EVENTS_C = $(OUTPUT)pmu-events/pmu-events.c
12-
METRIC_TEST_LOG = $(OUTPUT)pmu-events/metric_test.log
13-
TEST_EMPTY_PMU_EVENTS_C = $(OUTPUT)pmu-events/test-empty-pmu-events.c
14-
EMPTY_PMU_EVENTS_TEST_LOG = $(OUTPUT)pmu-events/empty-pmu-events.log
15-
LEGACY_CACHE_PY = pmu-events/make_legacy_cache.py
16-
LEGACY_CACHE_JSON = $(OUTPUT)pmu-events/arch/common/common/legacy-cache.json
4+
pmu-events-y += pmu-events.o
175

18-
ifeq ($(JEVENTS_ARCH),)
19-
JEVENTS_ARCH=$(SRCARCH)
20-
endif
21-
JEVENTS_MODEL ?= all
6+
# pmu-events.c file is generated in the OUTPUT directory so it needs a
7+
# separate rule to depend on it properly
8+
$(OUTPUT)pmu-events/pmu-events.o: $(PMU_EVENTS_C)
9+
$(call rule_mkdir)
10+
$(call if_changed_dep,cc_o_c)
2211

23-
#
24-
# Locate/process JSON files in pmu-events/arch/
25-
# directory and create tables in pmu-events.c.
26-
#
12+
# Message for $(call echo-cmd,cp), possibly remove the src file from
13+
# the destination to save space in the build log.
14+
quiet_cmd_cp = COPY $(patsubst %$<,%,$@) <- $<
2715

16+
# --- NO_JEVENTS=1 build ---
2817
ifeq ($(NO_JEVENTS),1)
2918
$(PMU_EVENTS_C): $(EMPTY_PMU_EVENTS_C)
3019
$(call rule_mkdir)
31-
$(Q)$(call echo-cmd,gen)cp $< $@
20+
$(Q)$(call echo-cmd,cp)cp $< $@
3221
else
33-
# Functions to extract the model from a extra-metrics.json or extra-metricgroups.json path.
34-
model_name = $(shell echo $(1)|sed -e 's@.\+/\(.*\)/extra-metric.*\.json@\1@')
35-
vendor_name = $(shell echo $(1)|sed -e 's@.\+/\(.*\)/[^/]*/extra-metric.*\.json@\1@')
22+
# --- Regular build ---
3623

37-
# Copy checked-in json to OUTPUT for generation if it's an out of source build
38-
ifneq ($(OUTPUT),)
39-
# Remove all output directories when any source directory timestamp changes
40-
# so there are no stale deleted files
41-
JSON_DIRS_ROOT = $(OUTPUT)pmu-events/arch/
42-
$(JSON_DIRS_ROOT): $(JSON_DIRS)
43-
$(Q)$(call echo-cmd,gen)rm -rf $@
44-
$(Q)mkdir -p $@
24+
# Setup the JEVENTS_ARCH and JEVENTS_MODEL
25+
ifeq ($(JEVENTS_ARCH),)
26+
JEVENTS_ARCH=$(SRCARCH)
27+
endif
28+
JEVENTS_MODEL ?= all
4529

46-
$(OUTPUT)pmu-events/arch/%: pmu-events/arch/% $(JSON_DIRS_ROOT)
47-
$(call rule_mkdir)
48-
$(Q)$(call echo-cmd,gen)cp $< $@
30+
# The input json/csv files
31+
SRC_DIR := pmu-events/arch
32+
ifeq ($(JEVENTS_ARCH),all)
33+
SRC_JSON := $(shell find $(SRC_DIR) -name '*.json' -o -name '*.csv')
34+
else
35+
SRC_JSON := $(shell find $(SRC_DIR)/common $(SRC_DIR)/test $(SRC_DIR)/$(JEVENTS_ARCH) -name '*.json' -o -name '*.csv')
4936
endif
5037

51-
$(LEGACY_CACHE_JSON): $(LEGACY_CACHE_PY) $(JSON_DIRS_ROOT)
38+
# Python to build the generic legacy cache events
39+
LEGACY_CACHE_PY = pmu-events/make_legacy_cache.py
40+
LEGACY_CACHE_JSON = $(OUTPUT)pmu-events/arch/common/common/legacy-cache.json
41+
GEN_JSON = $(LEGACY_CACHE_JSON)
42+
43+
$(LEGACY_CACHE_JSON): $(LEGACY_CACHE_PY)
5244
$(call rule_mkdir)
5345
$(Q)$(call echo-cmd,gen)$(PYTHON) $(LEGACY_CACHE_PY) > $@
5446

47+
# Python to generate architectural metrics
5548
GEN_METRIC_DEPS := pmu-events/metric.py pmu-events/common_metrics.py
49+
# Functions to extract the model from an extra-metrics.json or extra-metricgroups.json path.
50+
model_name = $(shell echo $(1)|sed -e 's@.\+/\(.*\)/extra-metric.*\.json@\1@')
51+
vendor_name = $(shell echo $(1)|sed -e 's@.\+/\(.*\)/[^/]*/extra-metric.*\.json@\1@')
5652

53+
ifeq ($(JEVENTS_ARCH),$(filter $(JEVENTS_ARCH),x86 all))
5754
# Generate AMD Json
5855
ZENS = $(shell ls -d pmu-events/arch/x86/amdzen*)
5956
ZEN_METRICS = $(foreach x,$(ZENS),$(OUTPUT)$(x)/extra-metrics.json)
6057
ZEN_METRICGROUPS = $(foreach x,$(ZENS),$(OUTPUT)$(x)/extra-metricgroups.json)
58+
GEN_JSON += $(ZEN_METRICS) $(ZEN_METRICGROUPS)
6159

6260
$(ZEN_METRICS): pmu-events/amd_metrics.py $(GEN_METRIC_DEPS)
6361
$(call rule_mkdir)
@@ -67,10 +65,14 @@ $(ZEN_METRICGROUPS): pmu-events/amd_metrics.py $(GEN_METRIC_DEPS)
6765
$(call rule_mkdir)
6866
$(Q)$(call echo-cmd,gen)$(PYTHON) $< -metricgroups $(call model_name,$@) pmu-events/arch > $@
6967

68+
endif
69+
70+
ifeq ($(JEVENTS_ARCH),$(filter $(JEVENTS_ARCH),arm64 all))
7071
# Generate ARM Json
7172
ARMS = $(shell ls -d pmu-events/arch/arm64/arm/*|grep -v cmn)
7273
ARM_METRICS = $(foreach x,$(ARMS),$(OUTPUT)$(x)/extra-metrics.json)
7374
ARM_METRICGROUPS = $(foreach x,$(ARMS),$(OUTPUT)$(x)/extra-metricgroups.json)
75+
GEN_JSON += $(ARM_METRICS) $(ARM_METRICGROUPS)
7476

7577
$(ARM_METRICS): pmu-events/arm64_metrics.py $(GEN_METRIC_DEPS)
7678
$(call rule_mkdir)
@@ -80,10 +82,14 @@ $(ARM_METRICGROUPS): pmu-events/arm64_metrics.py $(GEN_METRIC_DEPS)
8082
$(call rule_mkdir)
8183
$(Q)$(call echo-cmd,gen)$(PYTHON) $< -metricgroups $(call vendor_name,$@) $(call model_name,$@) pmu-events/arch > $@
8284

85+
endif
86+
87+
ifeq ($(JEVENTS_ARCH),$(filter $(JEVENTS_ARCH),x86 all))
8388
# Generate Intel Json
8489
INTELS = $(shell ls -d pmu-events/arch/x86/*|grep -v amdzen|grep -v mapfile.csv)
8590
INTEL_METRICS = $(foreach x,$(INTELS),$(OUTPUT)$(x)/extra-metrics.json)
8691
INTEL_METRICGROUPS = $(foreach x,$(INTELS),$(OUTPUT)$(x)/extra-metricgroups.json)
92+
GEN_JSON += $(INTEL_METRICS) $(INTEL_METRICGROUPS)
8793

8894
$(INTEL_METRICS): pmu-events/intel_metrics.py $(GEN_METRIC_DEPS)
8995
$(call rule_mkdir)
@@ -93,55 +99,130 @@ $(INTEL_METRICGROUPS): pmu-events/intel_metrics.py $(GEN_METRIC_DEPS)
9399
$(call rule_mkdir)
94100
$(Q)$(call echo-cmd,gen)$(PYTHON) $< -metricgroups $(call model_name,$@) pmu-events/arch > $@
95101

96-
GEN_JSON = $(patsubst %,$(OUTPUT)%,$(JSON)) \
97-
$(LEGACY_CACHE_JSON) \
98-
$(JSON_DIRS) \
99-
$(ZEN_METRICS) $(ZEN_METRICGROUPS) \
100-
$(ARM_METRICS) $(ARM_METRICGROUPS) \
101-
$(INTEL_METRICS) $(INTEL_METRICGROUPS)
102+
endif
103+
104+
OUT_DIR := $(OUTPUT)pmu-events/arch
105+
106+
ifeq ($(OUTPUT),)
107+
OUT_JSON := $(SRC_JSON)
108+
ORPHAN_FILES :=
109+
else
110+
# Things that need to be built in the OUTPUT directory. Note, ensure
111+
# there is a slash after the directory name so that it matches what
112+
# $(dir) gives in COPY_RULE.
113+
OUT_JSON := $(patsubst $(SRC_DIR)/%,$(OUT_DIR)/%,$(SRC_JSON))
114+
OUT_DIRS := $(sort $(patsubst %/,%,$(dir $(OUT_JSON))))
115+
116+
# Things already in the OUTPUT directory
117+
CUR_OUT_JSON := $(shell [ -d $(OUT_DIR) ] && find $(OUT_DIR) -type f)
118+
119+
# Things in the OUTPUT directory but shouldn't be there as computed by
120+
# OUT_JSON and GEN_JSON.
121+
ORPHAN_FILES := $(filter-out $(OUT_JSON) $(GEN_JSON),$(CUR_OUT_JSON))
122+
123+
# Message for $(call echo-cmd,mkd). There is already a mkdir message
124+
# but it assumes $@ is a file to mkdir the directory for.
125+
quiet_cmd_mkd = MKDIR $@
126+
127+
$(OUT_DIRS):
128+
$(Q)$(call echo-cmd,mkd)mkdir -p $@
129+
130+
# Explicitly generate rules to copy SRC_JSON files as $(dir) cannot
131+
# apply to $@ in a dependency. Exclude from the copy rules any that
132+
# look like they are copying generated json. This happens as a perf
133+
# build within the tools/perf directory will leave generated json
134+
# files within the tree, these then get picked up by SRC_JSON find.
135+
define COPY_RULE
136+
$(2): $(1) | $(3)
137+
$$(Q)$$(call echo-cmd,cp)cp $(1) $(2)
138+
endef
139+
$(foreach src,$(SRC_JSON), \
140+
$(eval dest := $(patsubst $(SRC_DIR)/%,$(OUT_DIR)/%,$(src))) \
141+
$(eval ddir := $(patsubst %/,%,$(dir $(dest)))) \
142+
$(if $(filter $(dest),$(GEN_JSON)),, \
143+
$(eval $(call COPY_RULE,$(src),$(dest),$(ddir))) \
144+
) \
145+
)
146+
147+
endif # ifneq ($(OUTPUT),)
148+
149+
JEVENTS_PY = pmu-events/jevents.py
150+
METRIC_PY = pmu-events/metric.py
151+
152+
# Rule to run the metric test.
153+
METRIC_TEST_PY = pmu-events/metric_test.py
154+
METRIC_TEST_LOG = $(OUTPUT)pmu-events/metric_test.log
102155

103156
$(METRIC_TEST_LOG): $(METRIC_TEST_PY) $(METRIC_PY)
104157
$(call rule_mkdir)
105158
$(Q)$(call echo-cmd,test)$(PYTHON) $< 2> $@ || (cat $@ && false)
106159

107-
$(TEST_EMPTY_PMU_EVENTS_C): $(GEN_JSON) $(JSON_TEST) $(JEVENTS_PY) $(METRIC_PY) $(METRIC_TEST_LOG)
160+
# Rule to create then ensure the empty-pmu-events.c is in sync.
161+
TEST_EMPTY_PMU_EVENTS_C = $(OUTPUT)pmu-events/test-empty-pmu-events.c
162+
EMPTY_PMU_EVENTS_TEST_LOG = $(OUTPUT)pmu-events/empty-pmu-events.log
163+
164+
$(TEST_EMPTY_PMU_EVENTS_C): $(OUT_JSON) $(GEN_JSON) $(JEVENTS_PY) $(METRIC_PY)
108165
$(call rule_mkdir)
109166
$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) none none $(OUTPUT)pmu-events/arch $@
110167

111168
$(EMPTY_PMU_EVENTS_TEST_LOG): $(EMPTY_PMU_EVENTS_C) $(TEST_EMPTY_PMU_EVENTS_C)
112169
$(call rule_mkdir)
113170
$(Q)$(call echo-cmd,test)diff -u $^ 2> $@ || (cat $@ && false)
114171

172+
173+
# Dependencies for jevents.py
174+
JEVENTS_DEPS := $(OUT_JSON) $(GEN_JSON) $(JEVENTS_PY) $(METRIC_PY) $(EMPTY_PMU_EVENTS_TEST_LOG) $(METRIC_TEST_LOG)
175+
176+
# Rules to run mypy if enabled.
115177
ifdef MYPY
116-
PMU_EVENTS_PY_TESTS := $(wildcard *.py)
117-
PMU_EVENTS_MYPY_TEST_LOGS := $(JEVENTS_PY_TESTS:%=%.mypy_log)
118-
else
119-
PMU_EVENTS_MYPY_TEST_LOGS :=
178+
define MYPY_RULE
179+
$(2): $(1)
180+
$$(Q)$$(call echo-cmd,test)mypy $(1) > $(2) || (cat $(2) && rm $(2) && false)
181+
endef
182+
$(foreach src,$(wildcard pmu-events/*.py), \
183+
$(eval dest := $(patsubst pmu-events/%,$(OUTPUT)pmu-events/%.mypy_log,$(src))) \
184+
$(eval $(call MYPY_RULE,$(src),$(dest))) \
185+
)
186+
187+
MYPY_INPUTS := $(wildcard pmu-events/*.py)
188+
MYPY_OUTPUTS := $(patsubst pmu-events/%,$(OUTPUT)pmu-events/%.mypy_log,$(MYPY_INPUTS))
189+
JEVENTS_DEPS += $(MYPY_OUTPUTS)
120190
endif
121191

122-
$(OUTPUT)%.mypy_log: %
123-
$(call rule_mkdir)
124-
$(Q)$(call echo-cmd,test)mypy "$<" > $@ || (cat $@ && rm $@ && false)
125-
192+
# Rules to run pylint if enabled.
126193
ifdef PYLINT
127-
PMU_EVENTS_PY_TESTS := $(wildcard *.py)
128-
PMU_EVENTS_PYLINT_TEST_LOGS := $(JEVENTS_PY_TESTS:%=%.pylint_log)
129-
else
130-
PMU_EVENTS_PYLINT_TEST_LOGS :=
194+
define PYLINT_RULE
195+
$(2): $(1)
196+
$$(Q)$$(call echo-cmd,test)pylint $(1) > $(2) || (cat $(2) && rm $(2) && false)
197+
endef
198+
$(foreach src,$(wildcard pmu-events/*.py), \
199+
$(eval dest := $(patsubst pmu-events/%,$(OUTPUT)pmu-events/%.pylint_log,$(src))) \
200+
$(eval $(call PYLINT_RULE,$(src),$(dest))) \
201+
)
202+
203+
PYLINT_INPUTS := $(wildcard pmu-events/*.py)
204+
PYLINT_OUTPUTS := $(patsubst pmu-events/%,$(OUTPUT)pmu-events/%.pylint_log,$(PYLINT_INPUTS))
205+
JEVENTS_DEPS += $(PYLINT_OUTPUTS)
131206
endif
132207

133-
$(OUTPUT)%.pylint_log: %
134-
$(call rule_mkdir)
135-
$(Q)$(call echo-cmd,test)pylint "$<" > $@ || (cat $@ && rm $@ && false)
208+
# If there are orphaned files remove them.
209+
ifneq ($(strip $(ORPHAN_FILES)),)
210+
.PHONY: prune_orphans
136211

137-
$(PMU_EVENTS_C): $(GEN_JSON) $(JSON_TEST) $(JEVENTS_PY) $(METRIC_PY) $(METRIC_TEST_LOG) \
138-
$(EMPTY_PMU_EVENTS_TEST_LOG) $(PMU_EVENTS_MYPY_TEST_LOGS) $(PMU_EVENTS_PYLINT_TEST_LOGS)
139-
$(call rule_mkdir)
140-
$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) $(JEVENTS_MODEL) $(OUTPUT)pmu-events/arch $@
212+
# Message for $(call echo-cmd,rm). Generally cleaning files isn't part
213+
# of a build step.
214+
quiet_cmd_rm = RM $^
215+
216+
prune_orphans: $(ORPHAN_FILES)
217+
$(Q)$(call echo-cmd,rm)rm -f $^
218+
219+
JEVENTS_DEPS += prune_orphans
141220
endif
142221

143-
# pmu-events.c file is generated in the OUTPUT directory so it needs a
144-
# separate rule to depend on it properly
145-
$(OUTPUT)pmu-events/pmu-events.o: $(PMU_EVENTS_C)
222+
# Finally, the rule to build pmu-events.c using jevents.py. All test
223+
# and inputs are dependencies.
224+
$(PMU_EVENTS_C): $(JEVENTS_DEPS)
146225
$(call rule_mkdir)
147-
$(call if_changed_dep,cc_o_c)
226+
$(Q)$(call echo-cmd,gen)$(PYTHON) $(JEVENTS_PY) $(JEVENTS_ARCH) $(JEVENTS_MODEL) $(OUT_DIR) $@
227+
228+
endif # ifeq ($(NO_JEVENTS),1)

0 commit comments

Comments
 (0)