Skip to content

Simple python library for generating your own perfetto traces for your application. Can be used for both app instrumentation and custom trace generation (for your own purposes)

License

Notifications You must be signed in to change notification settings

ihavnoid/tg4perfetto

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tg4perfetto

Simple python library for generating your own perfetto traces for your application.

Python application tracing

Example code (see tg4perfetto/example_profile.py for the code)

import tg4perfetto
import threading

# A "stat" counter.  This can be used to log integers or floating-point stats.
count_stats = tg4perfetto.count("num_active_threads")

# Normally, tracks are assigned to its thread's default track.  This creates a custom track
custom_track = tg4perfetto.track("TOP_TRACK")

# Log the event on a thread-default track.  trace_func_args logs the arguments put on the
# function, so be careful
@tg4perfetto.trace_func_args
def merge(x, x1, x2):
    # ... (omitted)

def merge_sort_wrapper(x, flow_id):
    # Instant events
    tg4perfetto.instant("START_THREAD", incoming_flow_ids = [flow_id[0]])
    custom_track.instant("START_THREAD", incoming_flow_ids = [flow_id[1]])

    return merge_sort(x)

def merge_sort_threaded(x):
    # Instant event.  Has two "flow ID" which can be used for connecting two events.
    flow_ids = tg4perfetto.instant("INVOKE_THREAD", num_outgoing_flow_ids = 2)

    t = threading.Thread(target=merge_sort_wrapper, args=(x,flow_ids))
    t.start()
    return (x, t)


# Log the event on a thread-default track.  Unlike trace_func_args, trace_func
# only logs the call in/out events.
@tg4perfetto.trace_func
def merge_sort(x):
    l = len(x)

    if l < 4096: return sorted(x)

    if l < 40000:
        x1 = merge_sort(x[:int(l/2)])
        x2 = merge_sort(x[int(l/2):])
    else:
        # Using count_stats to increment and decrement
        count_stats.increment(1)
        x1, t1 = merge_sort_threaded(x[:int(l/2)])
        count_stats.increment(1)
        x2, t2 = merge_sort_threaded(x[int(l/2):])
        t1.join()
        count_stats.increment(-1)
        t2.join()
        count_stats.increment(-1)
    
    return merge(x, x1, x2)

# Log the event on the given specific track.
@tg4perfetto.trace_func(custom_track)
def validate(xarray):
    # ... (omitted)

if __name__ == "__main__":
    # Start logging.  Logging stops when this goes out of scope.
    with tg4perfetto.open("tg4p.perfetto-trace"):

        # Use a custom track.
        # to put into the default track. just use tg4perfetto.trace(...) instead.
        with custom_track.trace('SORT').get_outgoing_flow_ids(1) as out_flow_id:
            xarray = [ (17 * x + 8) % 100 for x in range(100000) ]
            xarray = merge_sort(xarray)

            # Create one flow ID from the current track.  We can create flow IDs before closing the track.
            p = out_flow_id[0]

        # Set the incoming flow ID (optional, set only if there are any).
        with custom_track.trace('VALIDATE').set_incoming_flow_ids([p]):
            tg4perfetto.instant("CHECKING", {"final_result": xarray})
            validate(xarray)
            print("Done")

This will generate a trace file named "tg4p.perfetto-trace" which can be read from perfetto.

Custom packet generation

Example code (see tg4perfetto/example.py for the code)

# Packets can be created out-of-order.  This is because perfetto is designed to process out-of-order traces
# and reads all packets at once, rearranges them, and then visualizes it at once.
tgen = TraceGenerator(sys.argv[1])
pid = tgen.create_group("aaa", "example_track")
pid.open(100, "SOME_TRACK")
# "Flow" packet.  this will create an arrow from here to "open" event down there (400ns)
pid.close(250, [4])

# Global counter track
tid = tgen.create_counter_track("bbb")
tid.count(0, 3)
tid.count(200, 5)
tid.count(400, 7)
tid.count(700, 2)

# Counter track within the "aaa" group"
tid = pid.create_counter_track("bbb")
tid.count(0, 2)
tid.count(200, 4)
tid.count(400, 5)
tid.count(700, 1)

tid = pid.create_track("ddd")
tid.open(100, "WXX")
# another "flow" packet.
tid.close(300, [3])

tgen.flush()

pid = tgen.create_group("vvv")
tid = pid.create_counter_track("bbb2")
tid.count(0, 2)
tid.count(300, 400)
tid.count(400, 500)
tid.count(700, 1000)

tid = pid.create_track("ddd2")
tid2 = pid.create_track("ddd3")

tid2.instant(200, "WXYZ")
tid.open(222, "XXX")
tid2.open(300, "WXX3", {"aaa":"bbb", "ccc":"ddd"})
tid2.instant(300, "ABCDE", {"aaa": "bbb", "ccc": "xxx"})
tid.close(333)
# receives an arrow from the packet above.  this can be either from an instant event or a normal event.
tid2.open(400, "WXX4", {"aaa":"bbb", "ccc":"ddd"}, [3, 4])
tid2.instant(400, "ABCDE")

# Some annotation on instant event
tid2.instant(600, "ADE", {"aaa": "abc", "ccc": "xxx", "eee" : {"aaa": "abc", "ccc": "ddd"}})
tid2.close(670, [2])

# very complex annotations!
tid2.instant(700, "ADE2", {
    "aaa": "abc",
    "ccc": [1, 2, 3, 4, "a", "b", {"abcdef" : "fdsa", "ggg": True}],
    "eee" : {
        "aaa": "abc",
        "ccc": True,
        "eee": {
            "fff": "ggg",
            "hhh": 0x1234567
        }
    },
    "jjj": "kkk"
}, [2])
tid2.close(900, [1])
tid.open(900, "WXX2", {"aaa":"bbb", "ccc":"ddd"}, [1])
tid.close(1000)

pid4 = tgen.create_group("abc.2")
tid4 = pid4.create_group("XX")
t1 = tid4.create_track()
t2 = tid4.create_track()
t1.open(100, "X")
t2.open(300, "Y")
t1.close(500)
t2.close(600)

Example output:

Example screenshot

About

Simple python library for generating your own perfetto traces for your application. Can be used for both app instrumentation and custom trace generation (for your own purposes)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages