• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4"""
5Copyright (c) 2025 Huawei Device Co., Ltd.
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17"""
18
19from collections import defaultdict
20import json
21import logging
22import os
23import stat
24
25# Configure logging to display timestamps and messages
26logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s")
27
28
29def gen_parent(data):
30    """
31    Generate parent information for each event in the data.
32    This function sorts the events by timestamp and assigns a parent to each event
33    based on the conditions that the parent event must fully contain the current event
34    in terms of start time (ts) and duration (dur), and share the same process (pid) and thread (tid).
35    """
36    # Sort the data by timestamp (ts)
37    data = sorted(data, key=lambda x: x["ts"])
38    data_length = len(data)
39    for i in range(data_length):
40        current = data[i]  # Current event
41        current_end = current["ts"] + current["dur"]  # End time of the current event
42        for j in range(i - 1, -1, -1):  # Candidate parent event
43            candidate = data[j]
44            if candidate is None:
45                continue
46            candidate_end = candidate["ts"] + candidate["dur"]
47            # Check if the candidate event fully contains the current event
48            if (
49                candidate["ts"] <= current["ts"]
50                and candidate_end >= current_end
51                and candidate["pid"] == current["pid"]
52                and candidate["tid"] == current["tid"]
53            ):
54                # Assign the candidate event as the parent of the current event
55                current["parent"] = candidate["name"]
56                break
57        if "parent" in current and current["name"] == current["parent"]:
58            data[i] = None
59
60    data = [event for event in data if event is not None]
61    return data
62
63
64def re_gen_ts_and_dur(data_with_parent):
65    """
66    Regenerate timestamps (ts) and durations (dur) for events based on their parent relationships.
67    This function aggregates durations for events with the same parent and name,
68    and adjusts their timestamps to ensure correct ordering.
69    """
70    # Dictionary to store aggregated data
71    data_with_dur = {}
72    for event in data_with_parent:
73        name = event["name"]
74        parent = event.get("parent")
75        key = (parent, name)  # Use parent and name as a composite key
76        ts = int(event["ts"])
77        dur = int(event["dur"])
78        end = ts + dur
79        if key not in data_with_dur:
80            # Initialize the entry if the key doesn't exist
81            data_with_dur[key] = {
82                **event,
83                "ts": ts,
84                "dur": dur,
85                "end": end,
86            }
87        else:
88            # Aggregate durations for events with the same parent and name
89            data_with_dur[key]["dur"] += dur
90            data_with_dur[key]["end"] = (
91                data_with_dur[key]["ts"] + data_with_dur[key]["dur"]
92            )
93
94    # Convert the dictionary back to a list and sort by timestamp
95    re_data = list(data_with_dur.values())
96    re_data.sort(key=lambda x: x["ts"])
97
98    # Group events by their parent
99    groups = group_by_parent(re_data)
100
101    def get_parent_ts(parent_name, re_data):
102        """
103        Helper function to get the start time (ts) of a parent event.
104        Handles cases where the parent is a root node (no parent) or a non-root node.
105        """
106        if not parent_name:
107            return None  # Root node case
108        for event in re_data:
109            # Get the start time of the root node
110            if event["name"] == parent_name and "parent" not in event:
111                return event["ts"]
112        # Get the start time of a non-root node as a parent
113        for event in re_data:
114            if event["name"] == parent_name:
115                return event["ts"]
116        return None
117
118    # Flatten the grouped data and adjust timestamps based on parent relationships
119    flattened = []
120    for parent_name, nodes in groups.items():
121        if not nodes:
122            continue
123        nodes.sort(key=lambda x: x["ts"])
124        parent_ts = get_parent_ts(parent_name, re_data)
125        if parent_ts is not None:
126            # Adjust timestamps based on the parent's start time
127            nodes[0]["ts"] = parent_ts
128            nodes[0]["end"] = nodes[0]["ts"] + nodes[0]["dur"]
129            for i in range(1, len(nodes)):
130                nodes[i]["ts"] = nodes[i - 1]["end"]
131                nodes[i]["end"] = nodes[i]["ts"] + nodes[i]["dur"]
132        else:
133            # Adjust timestamps sequentially if no parent start time is available
134            current_end = nodes[0]["ts"] + nodes[0]["dur"]
135            for i in range(1, len(nodes)):
136                nodes[i]["ts"] = current_end
137                current_end = nodes[i]["ts"] + nodes[i]["dur"]
138                nodes[i]["end"] = current_end
139        flattened.extend(nodes)
140
141    # Save the flattened data to a JSON file
142    if os.path.exists('data.json'):
143        os.remove('data.json')
144    flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
145    modes = stat.S_IWUSR | stat.S_IRUSR
146    with os.fdopen(os.open('data.json', flags, modes), 'w') as file:
147        json.dump(flattened, file, indent=2)
148    return groups
149
150
151def group_by_parent(data):
152    """
153    Group events by their parent.
154    Events with the same parent are grouped together and sorted by timestamp.
155    """
156    groups = defaultdict(list)
157    for node in data:
158        parent = node.get("parent")
159        groups[parent].append(node)
160    for parent in groups:
161        groups[parent].sort(key=lambda x: x["ts"])
162    return dict(groups)
163
164
165if __name__ == "__main__":
166    # Load input data from a JSON file
167    with open("timePerformanceData.json", "r") as f:
168        datas = json.load(f)
169        # Generate parent information for each event
170        data_with_parents = gen_parent(datas)
171        # Regenerate timestamps and durations based on parent relationships
172        re_gen_ts_and_dur(data_with_parents)
173