Skip to content

Commit d0313e6

Browse files
captain5050acmel
authored andcommitted
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 <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: James Clark <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: John Garry <[email protected]> Cc: Kan Liang <[email protected]> Cc: Leo Yan <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mike Leach <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Ravi Bangoria <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Will Deacon <[email protected]> Cc: Xing Zhengjun <[email protected]> Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 9118259 commit d0313e6

File tree

1 file changed

+48
-7
lines changed

1 file changed

+48
-7
lines changed

tools/perf/pmu-events/jevents.py

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ class BigCString:
8080
are all the other C strings (to avoid memory issues the string
8181
itself is held as a list of strings). The offsets within the big
8282
string are recorded and when stored to disk these don't need
83-
relocation.
83+
relocation. To reduce the size of the string further, identical
84+
strings are merged. If a longer string ends-with the same value as a
85+
shorter string, these entries are also merged.
8486
"""
8587
strings: Set[str]
8688
big_string: Sequence[str]
@@ -96,6 +98,33 @@ def add(self, s: str) -> None:
9698
def compute(self) -> None:
9799
"""Called once all strings are added to compute the string and offsets."""
98100

101+
folded_strings = {}
102+
# Determine if two strings can be folded, ie. let 1 string use the
103+
# end of another. First reverse all strings and sort them.
104+
sorted_reversed_strings = sorted([x[::-1] for x in self.strings])
105+
106+
# Strings 'xyz' and 'yz' will now be [ 'zy', 'zyx' ]. Scan forward
107+
# for each string to see if there is a better candidate to fold it
108+
# into, in the example rather than using 'yz' we can use'xyz' at
109+
# an offset of 1. We record which string can be folded into which
110+
# in folded_strings, we don't need to record the offset as it is
111+
# trivially computed from the string lengths.
112+
for pos,s in enumerate(sorted_reversed_strings):
113+
best_pos = pos
114+
for check_pos in range(pos + 1, len(sorted_reversed_strings)):
115+
if sorted_reversed_strings[check_pos].startswith(s):
116+
best_pos = check_pos
117+
else:
118+
break
119+
if pos != best_pos:
120+
folded_strings[s[::-1]] = sorted_reversed_strings[best_pos][::-1]
121+
122+
# Compute reverse mappings for debugging.
123+
fold_into_strings = collections.defaultdict(set)
124+
for key, val in folded_strings.items():
125+
if key != val:
126+
fold_into_strings[val].add(key)
127+
99128
# big_string_offset is the current location within the C string
100129
# being appended to - comments, etc. don't count. big_string is
101130
# the string contents represented as a list. Strings are immutable
@@ -104,13 +133,25 @@ def compute(self) -> None:
104133
big_string_offset = 0
105134
self.big_string = []
106135
self.offsets = {}
107-
# Emit all strings in a sorted manner.
136+
137+
# Emit all strings that aren't folded in a sorted manner.
108138
for s in sorted(self.strings):
109-
self.offsets[s] = big_string_offset
110-
self.big_string.append(f'/* offset={big_string_offset} */ "')
111-
self.big_string.append(s)
112-
self.big_string.append('"\n')
113-
big_string_offset += c_len(s)
139+
if s not in folded_strings:
140+
self.offsets[s] = big_string_offset
141+
self.big_string.append(f'/* offset={big_string_offset} */ "')
142+
self.big_string.append(s)
143+
self.big_string.append('"')
144+
if s in fold_into_strings:
145+
self.big_string.append(' /* also: ' + ', '.join(fold_into_strings[s]) + ' */')
146+
self.big_string.append('\n')
147+
big_string_offset += c_len(s)
148+
continue
149+
150+
# Compute the offsets of the folded strings.
151+
for s in folded_strings.keys():
152+
assert s not in self.offsets
153+
folded_s = folded_strings[s]
154+
self.offsets[s] = self.offsets[folded_s] + c_len(folded_s) - c_len(s)
114155

115156
_bcs = BigCString()
116157

0 commit comments

Comments
 (0)