Skip to content

Instantly share code, notes, and snippets.

@VysotskiVadim
Last active February 28, 2023 04:07
Show Gist options
  • Save VysotskiVadim/31a3de8fd38729f179750b9dfed689e3 to your computer and use it in GitHub Desktop.
Save VysotskiVadim/31a3de8fd38729f179750b9dfed689e3 to your computer and use it in GitHub Desktop.
Build memory trendline
  1. Record perfetto traces using the instruction. Make sure phone has some available memory on disk. Increase max trace size and length. Record only memory-related activities to reduce trace file size. You can stop recording and start a new one. Put all tracess from the session to one directory on your computer.
  2. install Pyton3 brew install python3
  3. pip3 install pandas perfetto
  4. Run ./analyse.py pathToTraceFolder applicationId. Pass directory with traces and application id a parameter, for example if you have traces in directory testTraces and you want to build memory threndline for an application com.mapbox.navigation.examples, run ./analyse.py testTraces com.mapbox.navigation.examples

If analyse.py fails because random port allocation fails, try running it one more time.

Result of the trace is a chart with memory usage (blue) + trend line(red). It additionally output cooficient of the trenline linear function to command line, like rss trendline has coefficient -0.00034122302415542287. Positive coeficient means that value is groving, negative that memory usage is slowly decreasing, ideal value is close to 0.

#!/usr/bin/env python3
from cProfile import label
from datetime import timedelta
import sys
import pandas
import glob
from perfetto.batch_trace_processor.api import BatchTraceProcessor
import matplotlib.pyplot as plt
import numpy as np
# trendline https://www.statology.org/matplotlib-trendline/
def drawTrendLine(dataFrame, xKey, yKey, color, label):
ts = pandas.to_numeric(dataFrame[xKey])
mem = pandas.to_numeric(dataFrame[yKey])
coefficients = np.polyfit(ts, mem, 1)
b = coefficients[0]
print(f'{label} has coefficient {b:.20f}')
p = np.poly1d(coefficients)
plt.plot(ts, p(ts), color=color, label=label)
plt.legend()
tracesFolder = sys.argv[1]
packageName = sys.argv[2] if len(sys.argv) > 3 else 'com.mapbox.navigation.examples'
files = glob.glob(f'{tracesFolder}/*.perfetto-trace')
if (len(files) == 0):
print(f"no trace files found in {tracesFolder}")
exit()
print("loading:" + ' '.join(files))
with BatchTraceProcessor(files) as btp:
rssMemorySets = btp.query(f"select c.ts / 1000000 as timestamp, c.value / 1000 as rss from counter as c left join process_counter_track as t on c.track_id = t.id left join process as p using (upid) where t.name like 'mem.rss' and p.name like '{packageName}' order by c.ts")
rssMemory = pandas.concat(rssMemorySets)
rssMemory.sort_values(by=['timestamp'], inplace=True)
print(rssMemory.head())
rssMemory.plot(x='timestamp', y='rss')
drawTrendLine(rssMemory, xKey='timestamp', yKey='rss', color="red", label="rss trendline")
startOfTheTrace = rssMemory['timestamp'].iloc[0]
endOfTheTrace = rssMemory['timestamp'].iloc[-1]
traceDurationMilliseconds = (endOfTheTrace - startOfTheTrace)
delta = timedelta(milliseconds=traceDurationMilliseconds)
print("trace duration " + str(delta))
# heapSizeMemorySets = btp.query("select c.ts / 1000000 as timestamp, c.value / 1000 as heap from counter as c left join process_counter_track as t on c.track_id = t.id left join process as p using (upid) where t.name like 'Heap size (KB)' and p.name like 'com.mapbox.navigation.examples' order by c.ts")
# heapSize = pandas.concat(heapSizeMemorySets)
# heapSize.sort_values(by=['timestamp'], inplace=True)
# print(heapSize.head())
# heapSize.plot(x='timestamp', y='heap')
# drawTrendLine(heapSize, xKey='timestamp', yKey='heap', color="yellow", label="heap trendline")
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment