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>
This commit is contained in:
parent
9118259c1d
commit
d0313e629f
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in New Issue