perf scripts python: Implement add sample function and thread processing
authorAnup Sharma <anupnewsmail@gmail.com>
Fri, 21 Jul 2023 17:55:38 +0000 (23:25 +0530)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 28 Jul 2023 22:01:16 +0000 (19:01 -0300)
The intern_stack function is responsible for retrieving
or creating a stack_id based on the provided frame_id and prefix_id.
It first generates a key using the frame_id and prefix_id values.
If the stack corresponding to the key is found in the stackMap,
it is returned. Otherwise, a new stack is created by appending
the prefix_id and frame_id to the stackTable. The key
and the index of the newly created stack are added to the
stackMap for future reference.

The _intern_frame function is responsible for retrieving or
creating a frame_id based on the provided frame string. If the frame_id
corresponding to the frameString is found in the frameMap, it is
returned. Otherwise, a new frame is created by appending relevant
information to the frameTable and adding the frameString to the string_id
through _intern_string.

The _intern_string function will gets a matching string, or saves the new
string and returns a String ID.

Signed-off-by: Anup Sharma <anupnewsmail@gmail.com>
Link: https://lore.kernel.org/r/4442f4b1ab4c7317cf940560a3a285fcdfbeeb08.1689961706.git.anupnewsmail@gmail.com
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-perf-users@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/scripts/python/gecko.py

index 794a91bec464051a1fb80911a569abad317eb279..97949249a3c00a11acd0dd2308f8f644651aeeb4 100644 (file)
@@ -13,6 +13,7 @@ import os
 import sys
 import json
 import argparse
+from functools import reduce
 from dataclasses import dataclass, field
 from typing import List, Dict, Optional, NamedTuple, Set, Tuple, Any
 
@@ -39,6 +40,10 @@ CATEGORIES = None
 # The product name is used by the profiler UI to show the Operating system and Processor.
 PRODUCT = os.popen('uname -op').read().strip()
 
+# The category index is used by the profiler UI to show the color of the flame graph.
+USER_CATEGORY_INDEX = 0
+KERNEL_CATEGORY_INDEX = 1
+
 # https://github.com/firefox-devtools/profiler/blob/53970305b51b9b472e26d7457fee1d66cd4e2737/src/types/gecko-profile.js#L156
 class Frame(NamedTuple):
        string_id: StringID
@@ -99,6 +104,55 @@ class Thread:
        stackMap: Dict[Tuple[Optional[int], int], int] = field(default_factory=dict)
        frameMap: Dict[str, int] = field(default_factory=dict)
 
+       def _intern_stack(self, frame_id: int, prefix_id: Optional[int]) -> int:
+               """Gets a matching stack, or saves the new stack. Returns a Stack ID."""
+               key = f"{frame_id}" if prefix_id is None else f"{frame_id},{prefix_id}"
+               # key = (prefix_id, frame_id)
+               stack_id = self.stackMap.get(key)
+               if stack_id is None:
+                       # return stack_id
+                       stack_id = len(self.stackTable)
+                       self.stackTable.append(Stack(prefix_id=prefix_id, frame_id=frame_id))
+                       self.stackMap[key] = stack_id
+               return stack_id
+
+       def _intern_string(self, string: str) -> int:
+               """Gets a matching string, or saves the new string. Returns a String ID."""
+               string_id = self.stringMap.get(string)
+               if string_id is not None:
+                       return string_id
+               string_id = len(self.stringTable)
+               self.stringTable.append(string)
+               self.stringMap[string] = string_id
+               return string_id
+
+       def _intern_frame(self, frame_str: str) -> int:
+               """Gets a matching stack frame, or saves the new frame. Returns a Frame ID."""
+               frame_id = self.frameMap.get(frame_str)
+               if frame_id is not None:
+                       return frame_id
+               frame_id = len(self.frameTable)
+               self.frameMap[frame_str] = frame_id
+               string_id = self._intern_string(frame_str)
+
+               symbol_name_to_category = KERNEL_CATEGORY_INDEX if frame_str.find('kallsyms') != -1 \
+               or frame_str.find('/vmlinux') != -1 \
+               or frame_str.endswith('.ko)') \
+               else USER_CATEGORY_INDEX
+
+               self.frameTable.append(Frame(
+                       string_id=string_id,
+                       relevantForJS=False,
+                       innerWindowID=0,
+                       implementation=None,
+                       optimizations=None,
+                       line=None,
+                       column=None,
+                       category=symbol_name_to_category,
+                       subcategory=None,
+               ))
+               return frame_id
+
        def _to_json_dict(self) -> Dict:
                """Converts current Thread to GeckoThread JSON format."""
                # Gecko profile format is row-oriented data as List[List],