`professor`: Instrumentation based profiling library

Hi everyone,

For the past few months I have been working on professor, an instrumentation profiling library for Mojo, and I think with your feedback and contribution could shape into something that will be useful for the community.

Most profiling that I see online is carried out with the help of sampling profilers (like Instruments for Apple, perf for Linux and others). These are obviously very helpful and they belong to every developer’s toolbox.

professor being an instrumentation profiling library, takes the alternative approach: the programmer chooses profiling zones, however coarse or granular they want but instrumenting the code, i.e. explicitly marking them with Mojo code, and the profiler collects profiling metrics.

Here is a simplistic example, that highlights how to create your own profiler and open Profiling zones:

# Import the profiler and Instrument
from professor import Profiler, WallClock

# Define your global profiler
comptime Prof = Profiler[WallClock, Tag="wallclock-profiler”]

def do_work() -> Int:
    # Define a profiling zone with a `with` context.
    with Prof.zone[“work”]():
        # do work
        return # result

def so_more_work() -> Int:
    # Explicitly open and close the zone.
    var z = Prof.zone[“more-work”]()
    # do more work
    res = # result
    z^.close()
    return res

def main():
    # Start profiling session
    Prof.start()

    for i in range 100:
        do_work()
        do_more_work()

    for i in range(30):
        do_more_work()

    # End profiling session
    Prof.end()

    # Dump report in STDOUT
    Prof.report()

The _ProfileZone is a linear handle for the profiling zone. Being linear, it needs to be explicitly closed. This solves two problems. First, the zone does not close immediately because of ASAP destruction. Second, it solves another profiling bug at compile time, i.e. not closing properly a profiling zone, leading to erroneous metrics.

Each zone is assigned a semantic label in order to be easily distinguished from the others.

Any instrument that measures a profiling metric snapshot implements the Instrument trait and the associated Metric trait.

This way the user can define their own instruments without changing the metric collection logic.

For instance, the user can define an instrument that samples the invariant timestamp counter of the CPU, like cntpct_el0 in ARM (as the library already does) and rdtsc in x86 (not implemented yet).

In the end, the profiler will print a useful report to easily identify bottlenecks.

(The following report is from an example located in the repository. The form of the report is a work in progress. It can become more informative.).

These are examples of metrics that tell you where your code spends the most time. However, it is desirable to understand why it spends that time there.

For this professor provides an idiomatic interface to the OS performance monitoring frameworks, like kperf for Apple (implemented) and perf_events for Linux (work in progress).

These abstractions allow you to read the count for performance events like retired instructions, cache misses etc.

These Samplers can be used to create Instruments!

You can read the README for some more details: GitHub - gsmyridis/professor: Instrumentation profiling library for Mojo. · GitHub

The library is a work in progress, and I would love your feedback in terms of usefulness, design, and ergonomics!

Wow, this looks great! I do a ton of profiling, usually using overly-simplistic homemade tools, for lack of anything better at the moment. I’ll definitely try this out when you get the Linux support in there.