"""
Copyright (c) 2025 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from collections import defaultdict
import json
import logging
import os
import stat
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s")
def gen_parent(data):
"""
Generate parent information for each event in the data.
This function sorts the events by timestamp and assigns a parent to each event
based on the conditions that the parent event must fully contain the current event
in terms of start time (ts) and duration (dur), and share the same process (pid) and thread (tid).
"""
data = sorted(data, key=lambda x: x["ts"])
data_length = len(data)
for i in range(data_length):
current = data[i]
current_end = current["ts"] + current["dur"]
for j in range(i - 1, -1, -1):
candidate = data[j]
if candidate is None:
continue
candidate_end = candidate["ts"] + candidate["dur"]
if (
candidate["ts"] <= current["ts"]
and candidate_end >= current_end
and candidate["pid"] == current["pid"]
and candidate["tid"] == current["tid"]
):
current["parent"] = candidate["name"]
break
if "parent" in current and current["name"] == current["parent"]:
data[i] = None
data = [event for event in data if event is not None]
return data
def re_gen_ts_and_dur(data_with_parent):
"""
Regenerate timestamps (ts) and durations (dur) for events based on their parent relationships.
This function aggregates durations for events with the same parent and name,
and adjusts their timestamps to ensure correct ordering.
"""
data_with_dur = {}
for event in data_with_parent:
name = event["name"]
parent = event.get("parent")
key = (parent, name)
ts = int(event["ts"])
dur = int(event["dur"])
end = ts + dur
if key not in data_with_dur:
data_with_dur[key] = {
**event,
"ts": ts,
"dur": dur,
"end": end,
}
else:
data_with_dur[key]["dur"] += dur
data_with_dur[key]["end"] = (
data_with_dur[key]["ts"] + data_with_dur[key]["dur"]
)
re_data = list(data_with_dur.values())
re_data.sort(key=lambda x: x["ts"])
groups = group_by_parent(re_data)
def get_parent_ts(parent_name, re_data):
"""
Helper function to get the start time (ts) of a parent event.
Handles cases where the parent is a root node (no parent) or a non-root node.
"""
if not parent_name:
return None
for event in re_data:
if event["name"] == parent_name and "parent" not in event:
return event["ts"]
for event in re_data:
if event["name"] == parent_name:
return event["ts"]
return None
flattened = []
for parent_name, nodes in groups.items():
if not nodes:
continue
nodes.sort(key=lambda x: x["ts"])
parent_ts = get_parent_ts(parent_name, re_data)
if parent_ts is not None:
nodes[0]["ts"] = parent_ts
nodes[0]["end"] = nodes[0]["ts"] + nodes[0]["dur"]
for i in range(1, len(nodes)):
nodes[i]["ts"] = nodes[i - 1]["end"]
nodes[i]["end"] = nodes[i]["ts"] + nodes[i]["dur"]
else:
current_end = nodes[0]["ts"] + nodes[0]["dur"]
for i in range(1, len(nodes)):
nodes[i]["ts"] = current_end
current_end = nodes[i]["ts"] + nodes[i]["dur"]
nodes[i]["end"] = current_end
flattened.extend(nodes)
if os.path.exists('data.json'):
os.remove('data.json')
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
modes = stat.S_IWUSR | stat.S_IRUSR
with os.fdopen(os.open('data.json', flags, modes), 'w') as file:
json.dump(flattened, file, indent=2)
return groups
def group_by_parent(data):
"""
Group events by their parent.
Events with the same parent are grouped together and sorted by timestamp.
"""
groups = defaultdict(list)
for node in data:
parent = node.get("parent")
groups[parent].append(node)
for parent in groups:
groups[parent].sort(key=lambda x: x["ts"])
return dict(groups)
if __name__ == "__main__":
with open("timePerformanceData.json", "r") as f:
datas = json.load(f)
data_with_parents = gen_parent(datas)
re_gen_ts_and_dur(data_with_parents)