summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2022-08-12 16:09:49 -0700
committerArnaldo Carvalho de Melo <acme@redhat.com>2022-08-13 15:03:09 -0300
commitd0313e629f2690edfd269896b398048275227db0 (patch)
treebb18918250b13a30d8934fd6eea1172e70a148fc
parent9118259c1dc275e0f7b90da0d3cbaadc4e1ca3fe (diff)
downloadlwn-d0313e629f2690edfd269896b398048275227db0.tar.gz
lwn-d0313e629f2690edfd269896b398048275227db0.zip
perf jevents: Fold strings optimization
If a shorter string ends a longer string then the shorter string may reuse the longer string at an offset. For example, on x86 the event arith.cycles_div_busy and cycles_div_busy can be folded, even though they have difference names the strings are identical after 6 characters. cycles_div_busy can reuse the arith.cycles_div_busy string at an offset of 6. In pmu-events.c this looks like the following where the 'also:' lists folded strings: /* offset=177541 */ "arith.cycles_div_busy\000\000pipeline\000Cycles the divider is busy\000\000\000event=0x14,period=2000000,umask=0x1\000\000\000\000\000\000\000\000\000" /* also: cycles_div_busy\000\000pipeline\000Cycles the divider is busy\000\000\000event=0x14,period=2000000,umask=0x1\000\000\000\000\000\000\000\000\000 */ As jevents.py combines multiple strings for an event into a larger string, the amount of folding is minimal as all parts of the event must align. Other organizations can benefit more from folding, but lose space by say recording more offsets. Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@arm.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: John Garry <john.garry@huawei.com> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@linaro.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mike Leach <mike.leach@linaro.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ravi Bangoria <ravi.bangoria@amd.com> Cc: Stephane Eranian <eranian@google.com> Cc: Will Deacon <will@kernel.org> Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com> Cc: linux-arm-kernel@lists.infradead.org Link: https://lore.kernel.org/r/20220812230949.683239-15-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rwxr-xr-xtools/perf/pmu-events/jevents.py55
1 files changed, 48 insertions, 7 deletions
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index d722fcba2d9f..0daa3e007528 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -80,7 +80,9 @@ class BigCString:
are all the other C strings (to avoid memory issues the string
itself is held as a list of strings). The offsets within the big
string are recorded and when stored to disk these don't need
- relocation.
+ relocation. To reduce the size of the string further, identical
+ strings are merged. If a longer string ends-with the same value as a
+ shorter string, these entries are also merged.
"""
strings: Set[str]
big_string: Sequence[str]
@@ -96,6 +98,33 @@ class BigCString:
def compute(self) -> None:
"""Called once all strings are added to compute the string and offsets."""
+ folded_strings = {}
+ # Determine if two strings can be folded, ie. let 1 string use the
+ # end of another. First reverse all strings and sort them.
+ sorted_reversed_strings = sorted([x[::-1] for x in self.strings])
+
+ # Strings 'xyz' and 'yz' will now be [ 'zy', 'zyx' ]. Scan forward
+ # for each string to see if there is a better candidate to fold it
+ # into, in the example rather than using 'yz' we can use'xyz' at
+ # an offset of 1. We record which string can be folded into which
+ # in folded_strings, we don't need to record the offset as it is
+ # trivially computed from the string lengths.
+ for pos,s in enumerate(sorted_reversed_strings):
+ best_pos = pos
+ for check_pos in range(pos + 1, len(sorted_reversed_strings)):
+ if sorted_reversed_strings[check_pos].startswith(s):
+ best_pos = check_pos
+ else:
+ break
+ if pos != best_pos:
+ folded_strings[s[::-1]] = sorted_reversed_strings[best_pos][::-1]
+
+ # Compute reverse mappings for debugging.
+ fold_into_strings = collections.defaultdict(set)
+ for key, val in folded_strings.items():
+ if key != val:
+ fold_into_strings[val].add(key)
+
# big_string_offset is the current location within the C string
# being appended to - comments, etc. don't count. big_string is
# the string contents represented as a list. Strings are immutable
@@ -104,13 +133,25 @@ class BigCString:
big_string_offset = 0
self.big_string = []
self.offsets = {}
- # Emit all strings in a sorted manner.
+
+ # Emit all strings that aren't folded in a sorted manner.
for s in sorted(self.strings):
- self.offsets[s] = big_string_offset
- self.big_string.append(f'/* offset={big_string_offset} */ "')
- self.big_string.append(s)
- self.big_string.append('"\n')
- big_string_offset += c_len(s)
+ if s not in folded_strings:
+ self.offsets[s] = big_string_offset
+ self.big_string.append(f'/* offset={big_string_offset} */ "')
+ self.big_string.append(s)
+ self.big_string.append('"')
+ if s in fold_into_strings:
+ self.big_string.append(' /* also: ' + ', '.join(fold_into_strings[s]) + ' */')
+ self.big_string.append('\n')
+ big_string_offset += c_len(s)
+ continue
+
+ # Compute the offsets of the folded strings.
+ for s in folded_strings.keys():
+ assert s not in self.offsets
+ folded_s = folded_strings[s]
+ self.offsets[s] = self.offsets[folded_s] + c_len(folded_s) - c_len(s)
_bcs = BigCString()