import sys
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from collections import defaultdict
def parse_memory_data(csv_data):
df = pd.read_csv(
csv_data,
names=["timestamp", "operation", "pointer", "parent", "type", "size"],
dtype={
"timestamp": np.int64,
"operation": str,
"pointer": str,
"parent": str,
"type": str,
"size": np.float64,
},
usecols=["timestamp", "operation", "pointer", "parent", "type", "size"],
)
df = df[df["parent"].apply(lambda x: int(x, 16) == 0)]
df["size"] = df["size"] / (1024 * 1024)
df = df.sort_values("timestamp")
memory_by_type = defaultdict(lambda: defaultdict(float))
memory_values_by_type = defaultdict(list)
chunk_size = 10000
for chunk_start in range(0, len(df), chunk_size):
chunk = df.iloc[chunk_start : chunk_start + chunk_size]
for _, row in chunk.iterrows():
mem_type = row["type"]
pointer = row["pointer"]
timestamp = row["timestamp"] / 1000000000.0
if row["operation"] == "alloc":
memory_by_type[mem_type][pointer] = row["size"]
elif pointer in memory_by_type[mem_type]:
del memory_by_type[mem_type][pointer]
current_memory = sum(memory_by_type[mem_type].values())
buffer_count = len(memory_by_type[mem_type])
extra_info = ""
if row["operation"] == "alloc" or row["operation"] == "free":
extra_info = f"{row['operation']}(0x{pointer}={row['size']:.3f}MB)"
memory_values_by_type[mem_type].append(
(timestamp, current_memory, buffer_count, extra_info)
)
return memory_values_by_type
def create_memory_graph(csv_data):
memory_values_by_type = parse_memory_data(csv_data)
fig = go.Figure()
colors = {
"SystemMemory": "blue",
"GPU Memory": "red",
"GLBuffer": "orange",
"GLMemoryPBO": "darkorange",
"GLRenderBuffer": "darkturquoise",
"gst.cuda.memory": "green",
"DMABuf": "purple",
"fd": "magenta",
"shm": "darkviolet",
}
for mem_type, values in memory_values_by_type.items():
color = colors.get(mem_type, "gray")
decimation_factor = max(1, len(values) // 10000)
decimated_values = values[::decimation_factor]
decimated_timestamps = [v[0] for v in decimated_values]
memory_values = [v[1] for v in decimated_values] buffer_counts = [v[2] for v in decimated_values] extra_info = [v[3] for v in decimated_values] extra_info = [v[2] for v in decimated_values]
hover_text = [
f"{mem_type}:<br>• Size: {mem:.2f}MB<br>• Buffers: {count}"
for mem, count, _ in zip(memory_values, buffer_counts, extra_info)
]
fig.add_trace(
go.Scatter(
x=decimated_timestamps,
y=memory_values,
mode="lines", name=f"{mem_type}",
line=dict(color=color, width=2),
hovertext=hover_text,
hoverinfo="text",
hovertemplate="%{hovertext}<extra></extra>", )
)
fig.update_layout(
title="GStreamer Memory Usage Over Time",
xaxis_title="Timestamp",
yaxis_title="Memory Usage (MB)",
hovermode="x unified",
showlegend=True,
template="plotly_white",
yaxis=dict(rangemode="nonnegative"), )
return fig
if __name__ == "__main__":
csv_data = sys.argv[1]
fig = create_memory_graph(csv_data)
fig.show()