AI assistance

Some textual parts of the documentation here are AI-generated/AI-assisted. A human Adaptyst developer has verified everything here and made polishes wherever needed.

After running Adaptyst, you can analyse its results with a separate program called Adaptyst Analyser.

Modules in Adaptyst Analyser

You must install the same modules you use in Adaptyst in Adaptyst Analyser. Each module comes with its Adaptyst Analyser part that can be set up by running:

adaptyst-analyser <path to the Adaptyst Analyser module directory>

You can check the list of currently-installed modules in Adaptyst Analyser by running adaptyst-analyser -l.

Web server / Interactive website

The main functionality of Adaptyst Analyser is a web server serving the interactive website for browsing performance analysis results produced e.g. by Adaptyst.

The server can be started by running:

adaptyst-analyser <path to results>

where <path to results> is the path to a directory containing result folders created e.g. by Adaptyst. For configuration options, see adaptyst-analyser --help.

Help message printed by adaptyst-analyser --help
usage: adaptyst-analyser [-h] [--version] [-a ADDR] [-s ADDR] [-t TITLE] [-b CSS] [--force-install] [-u] [-d] [-l]
                         [--password-stdin | --password-env]
                         [PATH]

Adaptyst Analyser web server

positional arguments:
  PATH              relative or absolute path to a performance analysis results directory to inspect or an Adaptyst Analyser module
                    directory to install

optional arguments:
  -h, --help        show this help message and exit
  --version         print version and exit
  -a ADDR           address and port to bind to, default: 127.0.0.1:8000
  -s ADDR           database to connect to for storing arrangements (use the SQLAlchemy database URL syntax), a user-local SQLite database
                    is created and used by default
  -t TITLE          custom title to be displayed alongside "Adaptyst Analyser" (e.g. if set to XYZ, the displayed entire title will be
                    "Adaptyst Analyser (XYZ)")
  -b CSS            custom background CSS of the website (syntax is the same as in "background" in CSS, do not use semicolons)
  --force-install   (re)install all core JavaScript dependencies even if they are already set up
  -u                update/reinstall the module if it is already installed
  -d                install the module in development mode
  -l                list in detail all installed Adaptyst Analyser modules
  --password-stdin  read database password from stdin (-s must be used)
  --password-env    read database password from the ADAPTYST_ANALYSER_DB_PASSWORD environment variable (-s must be used)

When adaptyst-analyser is run, look out for an output line similar to this:

[2024-10-12 13:57:52 +0200] [2192] [INFO] Listening at: http://127.0.0.1:8000 (2192)

The address points to the website where you can browse your profiling results.

Under the hood, Gunicorn and Flask are used (set up automatically when installing Adaptyst Analyser).

If you prefer not to use adaptyst-analyser or you cannot use it, set the FLASK_PROFILING_STORAGE environment variable to the path to a results directory and start the adaptystanalyser.app:app Flask app using a method of your choice.

Using results from other programs than Adaptyst

While Adaptyst Analyser is designed with Adaptyst in mind, it can be used with any other profiler which produces result files in the Adaptyst format.

You can check the “Structure of results” box in Running Adaptyst and the source code of Adaptyst along with its open-source modules for learning how it formats its profiling results.

Website navigation

The website is a window-based system: you start with the main view which is able to host multiple internal windows. You can open as many windows as you wish and every window can be freely moved, resized, and collapsed (by clicking the eye icon in a title bar). All windows persist across performance analysis sessions (so you can e.g. open two windows side-by-side from two different sessions).

After opening the website, follow these two steps:

  1. Select your performance analysis session from the “Please select a performance analysis session” combobox and wait until the session loads.
  2. You will see a visualisation of the system graph of the session. Double-click your node of choice to open more information related to the node as provided by the modules attached to it. The way this is displayed is module-dependent: follow the documentation of the modules.

See the video demo below showing some performance analysis results of two ROOT code snippets (before and after heterogeneous-computing-related optimisations). The version of Adaptyst Analyser presented there is 0.1.0.dev4, before the license change to GNU LGPL v3+. The modules featured are linuxperf and nvgpu. Window arrangements are not demonstrated here, see the section below instead.

Window tips

  • If you want to quickly refresh your window or revert its state to the original one (one use case for this in the context of linuxperf is going back to the beginning when analysing a complex flame graph with lots of custom regex-based replacements), click the “refresh” icon in the window header.
  • If you want to rename the title of a window (e.g. to make it easier to distinguish multiple windows of the same type), click the “rename” icon in the window header.

Sharing results or parts of it with others

To share easily performance analysis results or parts of it with others, you can either generate a session link or use window arrangements:

  • When a session link is opened, Adaptyst Analyser loads the indicated performance analysis session automatically.
  • A window arrangement contains the selected performance analysis session, system graph camera position, and all currently-open windows with their sizes, positions, and state. When a module supports exporting window content, that content is also saved.
  • A single window arrangement contains just a given window along with the windows it depends on. This is useful e.g. for sharing a specific visualisation without the rest of your workspace.

To generate a session link, click the share button in the website header to open the share menu and select “Get session link” there. Adaptyst Analyser will then open a window containing a link to the session which is currently loaded.

Window arrangements

To save a window arrangement, click the share button in the website header to open the share menu and select “Save window arrangement” there. Enter a unique name or leave the name empty to make the server generate a human-friendly one automatically. Afterwards, Adaptyst Analyser displays an update token and opens a window containing a link to the arrangement. The token is shown once only, so save it in a safe place!

If you want to save a single window arrangement, click the share icon in the title bar of a window you’d like to save, then give a name for your arrangement or leave it empty to make the server generate a human-friendly one. Afterwards, as for window arrangements, Adaptyst Analyser displays an update token and opens a window containing a link to the arrangement.

Click the “Open a saved arrangement” icon in the website header to browse saved arrangements. The list can be searched, filtered by arrangement type, and sorted.

Arrangements are stored in a database: by default, Adaptyst Analyser uses an automatically-created user-local SQLite database. If you want, you can point Adaptyst Analyser to a different database by running it with -s: use the SQLAlchemy syntax there. A database password can be provided either as part of an SQLAlchemy database URL, through standard input (use --password-stdin for this), or through the ADAPTYST_ANALYSER_DB_PASSWORD environment variable (use --password-env for this).

Adaptyst Analyser checks the fingerprint of every performance analysis session referenced by an arrangement before opening it. If any session is missing or recently-changed, an error is thrown.

Compact mode

When a session or an arrangement is loaded in Adaptyst Analyser through a custom link, you can use the compact mode: this version of the interactive website is more friendly towards smaller screen sizes and embedding via iframe. Mobile phones are not supported though.

The figure below shows an example of a session opened in the compact mode: tabs are used instead of windows and the header/footer is accordingly smaller and can be hidden (also by default if this is provided in the link). The full size of the screenshot can be found here.

For more information, see Interactive website URL parameters.

Adaptyst Analyser screenshot showcasing the compact mode with a flame graph in the currently-focused tab
A real-world Adaptyst performance analysis session performed on ROOT (see "Python API" below) opened in Adaptyst Analyser in the compact mode.

Python API

Adaptyst Analyser can be imported as a Python package to inspect performance analysis results and export data without starting its web server.

The usual flow is:

  1. Instantiate a Session object for a given result.
  2. Query the system graph, e.g. select an entity and one of its nodes/edges and obtain a module attached to it (the module then provides methods for processing its data).
  3. Optionally, ask the module for one or more window objects, save them as an arrangement with Window.save_arrgmt(), and build a web link that a user running the same Adaptyst Analyser web server can open to get these windows at the interactive website.

The examples below use a real-world Adaptyst performance analysis session performed with linuxperf on ROOT (commit b7bf155) running df103_NanoAODHiggsAnalysis.C (no JIT symbols are present). The session archive can be downloaded here.

Querying the system graph and accessing modules

Session loads a given result directory, including its system graph. The entities, nodes, edges, and modules can then be traversed directly as Python objects:

from pathlib import Path
from adaptystanalyser import Session

result_path = Path("results/root_df103")

# Load the result.
session = Session(result_path)

# Iterate over all entities and their nodes in the system graph.
entities = session.get_entities_iterable()
nodes = [node
         for entity in entities
         for node in entity.get_nodes_iterable()]

print("session:", session.identifier)
print("entities:", sorted(entity.name for entity in entities))
print("nodes:", [f"[{node.entity.name}] {node.name}" for node in nodes])
Example printed output
session: ROOT df103 (2026-07-02 14:41:48)
entities: ['xyz']
nodes: ['[xyz] abc']

You can also look graph elements up directly by their name:

entity = session.get_entity("xyz")
node = entity.get_node("abc")
linuxperf = node.get_module("linuxperf")

print("module:", linuxperf.get_name())
Example printed output
module: linuxperf

Important

The by-name query methods return None when the corresponding graph elements don’t exist!

When a Session object is constructed, Adaptyst Analyser imports every module used by the session. However, result data are loaded lazily, so potentially expensive module setup work is performed only when first actual queries are made or even later (depending on how modules are implemented).

Please consult the documentation of specific modules for information about how you can process data obtained by them via the Python API (in case of this example: linuxperf).

Exporting windows

Modules can provide Python objects corresponding to windows/tabs in the interactive website. For example, this code exports the timeline window of the linuxperf module (it should be read together with the previous snippets):

from adaptystanalyser import Window

# Ask linuxperf for a window displaying the process/thread timeline.
timeline_window = linuxperf.get_timeline_window()

# Serialise the window and save the arrangement.
arrangement_id, update_token = Window.save_arrgmt(
    timeline_window,
    name="root-df103-timeline",
)

# get_arrgmt_url() returns a URL suffix for an Adaptyst
# Analyser web server.
#
# "http://127.0.0.1:8000" is just an example, use your web
# server address instead.
url = "http://127.0.0.1:8000" + Window.get_arrgmt_url(arrangement_id)

print("arrangement:", arrangement_id)
print("URL:", url)
print("update token:", update_token)
Example printed output (token not shown)
arrangement: 1
URL: http://127.0.0.1:8000/?arrgmt=1&compact=1&hide_header=1&hide_footer=1
update token: (token)

By default, Window.save_arrgmt() connects to the user-local SQLite database created automatically under the hood (a different database can also be used: see the Window.save_arrgmt() docstring). If name is omitted, Adaptyst Analyser generates a random human-friendly name and returns it as a third tuple element. Store the update token securely: it is needed to rename or delete the arrangement and cannot be retrieved later.

Passing a single window object creates a single window arrangement while passing a list of window objects creates a window arrangement. If you decide to make a window arrangement, remember to include all necessary dependencies in the list.

For the URL to work, run the Adaptyst Analyser web server pointing to the same database and parent results directory.

Reference

The complete Python API reference can be found here.

REST API

The Adaptyst Analyser web server exposes an HTTP API alongside its interactive website. It can retrieve a session’s system graph, send requests to an Adaptyst Analyser module, and save or retrieve window arrangements.

POST parameters are read from form fields. A JSON request body is not supported. Responses containing JSON should be parsed as JSON even when the server does not set a JSON content type.

System graph

GET /get/<session>/

Returns the system graph for a performance analysis session <session>, where <session> is the name of a result directory inside the path defined when starting the Adaptyst Analyser instance.

NameValue typeRequiredDescription
<session>URL-encoded stringYesName of the performance analysis session directory.

The successful response is a JSON object in the Sigma.js/Graphology import format:

{
  "entities": {
    "<name of the entity>": ["<exit status code of the entity>", "<colour assigned to the entity>"]
  },
  "system": {
    "options": {
      "allowSelfLoops": false,
      "multi": false,
      "type": "directed"
    },
    "nodes": [
      {
        "key": "<unique key of the node>",
        "attributes": {
          "x": "<horizontal coordinate of the node>",
          "y": "<vertical coordinate of the node>",
          "label": "<label displayed for the node>",
          "server_id": "<identifier of the node on the server>",
          "size": 40,
          "color": "<colour assigned to the entity>",
          "entity": "<name of the entity>",
          "backends": [["<name of a module used>", "<version of the module used>"]]
        }
      }
    ],
    "edges": [
      {
        "key": "<unique key of the edge>",
        "source": "<unique key of the edge's source node>",
        "target": "<unique key of the edge's target node>",
        "undirected": false,
        "attributes": {
          "label": "<label displayed for the edge>",
          "size": 10
        }
      }
    ]
  }
}

entities maps each entity name to [exit_code, colour]. Each node’s backends lists what Adaptyst modules were used along with their versions so that corresponding Adaptyst Analyser modules can be deployed. Node coordinates are generated for the response and should not be considered persistent layout data.

In future versions of Adaptyst Analyser, backends may be present also in edges.

The HTTP status codes are as follows:

StatusMeaning
200The session was found and its graph was returned.
404The session directory was not found.

Module requests

POST /process/<session>/<entity>/<analysable>/<module>

Forwards a form request to a module for a node or edge in a session. This is used to query or update module-specific analysis results.

NameValue typeRequiredDescription
<session>URL-encoded stringYesPerformance analysis session directory name.
<entity>URL-encoded stringYesID of an entity from the system graph.
<analysable>URL-encoded stringYesID of a node or edge in the entity.
<module>URL-encoded stringYesModule name listed in the target’s backends.

The allowed form fields, their meaning, and the response format are defined by the target module: please consult its documentation.

The HTTP status codes are as follows:

StatusMeaning
200The module processed the request. The response format is module-specific.
404The session, entity, analysable, or module was not found, or the module raised Python ValueError.

The module may return a status code different from the ones above: see its documentation if needed.

POST /process/<session>/<analysable>/<module>

This will be fully supported in future versions of Adaptyst Analyser, once the support for inter-entity edges is implemented.

Window arrangements

POST /arrgmt

Manages saved window arrangements. Every request needs a type form field; the remaining fields depend on its value. Arrangement data is the JSON serialisation of an Adaptyst Analyser window arrangement: this can be produced on the web client side by calling Window.serialize() in JavaScript (see Module development) or in the Python API by calling Window.get_arrgmt_json().

Check a name

Use type=check_name to test whether an arrangement with a given name already exists.

NameValue typeRequiredDescription
typeString: check_nameYesRequest operation.
nameStringNoArrangement name to test.

The response is a JSON object in the following format:

{"exists": "<true if an arrangement with this name exists, otherwise false>"}

When name is omitted, the response is always {"exists": false}.

Save an arrangement

Use type=save to create an arrangement. A successful save returns the update token. Store it securely because it cannot be retrieved later.

NameValue typeRequiredDescription
typeString: saveYesRequest operation.
dataString containing a JSON objectYesWindow arrangement serialisation.
nameStringNoUnique arrangement name. Omit it to generate a human-friendly name.

With an explicit name, the response is:

{
  "id": "<identifier of the saved arrangement>",
  "token": "<token required to rename or delete the arrangement>"
}

When name is omitted, the response additionally contains the generated name:

{
  "id": "<identifier of the saved arrangement>",
  "name": "<human-friendly name generated by the server>",
  "token": "<token required to rename or delete the arrangement>"
}

Rename an arrangement

Use the update token returned by save to rename an arrangement.

NameValue typeRequiredDescription
typeString: edit_nameYesRequest operation.
nameStringYesCurrent arrangement name.
new_nameStringYesNew unique arrangement name.
tokenStringYesUpdate token.

A successful response is the empty JSON object {}.

Delete an arrangement

Use the update token returned by save to delete an arrangement.

NameValue typeRequiredDescription
typeString: deleteYesRequest operation.
nameStringYesArrangement name.
tokenStringYesUpdate token.

A successful response is the empty JSON object {}.

Retrieve an arrangement

Use type=get with exactly one of id or name. The response is the exact JSON arrangement serialisation supplied when it was saved.

NameValue typeRequiredDescription
typeString: getYesRequest operation.
idIntegerYes: either id or nameArrangement identifier.
nameStringYes: either id or nameArrangement name.

Before returning an arrangement, the server verifies fingerprints of the sessions referenced by it. If a referenced session is missing or has changed, the response is:

{"session_invalid": "<name of the missing or changed session>"}

Behaviour in case of multiple invalid sessions

If several sessions are missing or recently-changed, only the first encountered erroneous session is reported.

Otherwise, the response is the JSON arrangement serialisation supplied in the data field when the arrangement was saved.

List arrangements

Use type=list to obtain arrangement metadata with optional filtering, pagination, sorting, and type selection.

NameValue typeRequiredDescription
typeString: listYesRequest operation.
searchRegex stringNoFilter arrangement names using a regex. Omit it to disable regex filtering.
limitIntegerNoMaximum results per page. Defaults to 10.
pageIntegerNoPage number. Defaults to 1.
sortString: one of last_update_desc, last_update_asc, name_desc, name_ascNoResult order. Defaults to last_update_desc.
typesString: one of W, SW, bothNoArrangement type filter. W means “window arrangement” and SW means “single window arrangement”. Defaults to both.

The response is a JSON object in the following format:

{
  "general_total_cnt": "<total number of matching arrangements>",
  "general_total_pages": "<total number of result pages>",
  "list": [
    {
      "id": "<identifier of the arrangement>",
      "name": "<name of the arrangement>",
      "type": "<W for a window arrangement or SW for a single window arrangement>",
      "last_update": "<date and time when the arrangement was last updated>"
    }
  ]
}

Arrangement status codes

StatusMeaning
200The request succeeded.
400type or a required field is missing, the request type is unknown, or list parameters are invalid.
403The update token for a rename or delete request is missing or invalid.
404The requested arrangement does not exist.
409Saving with an existing name or renaming to an existing name was attempted.
422An arrangement was found, but a session it references is unavailable or has changed. The response identifies that session in session_invalid.

Interactive website URL parameters

GET / points to the interactive website and is separate from the REST API, but its query parameters can be useful when linking to an arrangement or a session:

NameValue typeRequiredDescription
sessionStringNoA session in the viewer to be opened.
arrgmtIntegerNoThe identifier of an arrangement to be opened.
compact1NoWhether compact mode should be enabled: set it to 1 for yes or omit it for no. If yes, a session or arrangement is required.
hide_header1NoWhether the header should be hidden by default in compact mode: set it to 1 for yes or omit it for no.
hide_footer1NoWhether the footer should be hidden by default in compact mode: set it to 1 for yes or omit it for no.

For example, http://127.0.0.1:8000/?arrgmt=42 opens arrangement with ID 42 in a web browser.