SkillAgentSearch skills...

Palanteer

Visual Python and C++ nanosecond profiler, logger, tests enabler

Install / Use

/learn @dfeneyrou/Palanteer

README

Look into Palanteer and get an omniscient view of your program

Build Status

Palanteer is a set of lean and efficient tools to improve the quality of software, for C++ and Python programs.

<img src="docs/images/views.gif " alt="Palanteer viewer image" width="1000"/>

Simple code instrumentation, mostly automatic in Python, delivers powerful features:

  • Collection of meaningful atomic events on timings, memory, locks wait and usage, context switches, data values..
  • Efficient logging with a printf-compatible interface
  • Visual and interactive observation of records: hierarchical logs, timeline, plot, histogram, flame graph...
  • Remote command call and events observation can be scripted in Python: deep testing has never been simpler
  • C++:
  • Python:
    • Automatic instrumentation of functions enter/leave, memory allocations, raised exceptions, garbage collection runs
    • Seamless support of multithreading, asyncio/gevent

Recording simultaneously up to 8 streams (i.e., from different processes) is supported.

Palanteer is an efficient, lean and comprehensive solution for better and enjoyable software development!

C++ instrumentation example

Below is a simple example of a C++ program instrumented with Palanteer and generating 100 000 random integers. The range can be remotely configured with a user-defined CLI.

The Python scripting module can control this program, in particular:

  • call the setBoundsCliHandler to change the configuration
  • temporarily stop the program at the freeze point
  • see all "random data" values and the timing of the scope event "Generate some random values"
<details> <summary> See C++ example code </summary>
// File: example.cpp
// On Linux, build with:  g++ -DUSE_PL=1 -I <palanteer C++ instrumentation folder> example.cpp -lpthread -o example
#include <stdlib.h>          // For "rand"
#define PL_IMPLEMENTATION 1  // The instrumentation library shall be "implemented" once
#include "palanteer.h"

int globalMinValue = 0, globalMaxValue = 10;

// Handler (=user implementation) of the example CLI, which sets the range
void setBoundsCliHandler(plCliIo& cio)             // 'cio' is a communication helper passed to each C++ CLI handler
{
    int minValue = cio.getParamInt(0);             // Get the 2 CLI parameters as integers (as declared)
    int maxValue = cio.getParamInt(1);
    if(minValue>maxValue) {                        // Case where the CLI execution fails. The text answer contains some information about it
        cio.setErrorState("Minimum value (%d) shall be lower than the maximum value (%d)", minValue, maxValue);
        return;
    }

    // Modify the state of the program. No care about thread-safety here, to keep the example simple
    globalMinValue = minValue;
    globalMaxValue = maxValue;
    // CLI execution was successful (because no call to cio.setErrorState())
}


int main(int argc, char** argv)
{
    plInitAndStart("example");              // Start the instrumentation, for the program named "example"
    plDeclareThread("Main");                // Declare the current thread as "Main" so that it can be identified more easily in the script
    plRegisterCli(setBoundsCliHandler, "config:setRange", "min=int max=int", "Sets the value bounds of the random generator");  // Declare our CLI
    plFreezePoint();                        // Add a freeze point here to be able to configure the program at a controlled moment

    plBegin("Generate some random values");
    for(int i=0; i<100000; ++i) {
        int value = globalMinValue + rand()%(globalMaxValue+1-globalMinValue);
        plData("random data", value);       // Here are the "useful" values
    }
    plEnd("");                              // Shortcut for plEnd("Generate some random values")

    plStopAndUninit();                      // Stop and uninitialize the instrumentation
    return 0;
}
</details>

Some C++ performance figures (see here for more details):

  • nanosecond resolution and ~25 nanoseconds cost per event on a standard x64 machine
  • up to ~5 millions events per second when recording, bottleneck on the server processing side
  • up to ~150 000 events per second when processing the flow through a Python script, bottleneck on the Python script side

Python instrumentation example

Execution of unmodified Python programs can be analyzed directly with a syntax similar to the one of cProfile, as a large part of the instrumentation is automated by default:

  • Functions enter/leave
  • Interpreter memory allocations
  • All raised exceptions
  • Garbage collection runs
  • Coroutines

In some cases, a manual instrumentation which enhances or replaces the automatic one is desired. <br/> The example below is an equivalent of the C++ code above, but in Python:

<details> <summary> See Python manual instrumentation example code </summary>
#! /usr/bin/env python3
import sys
import random
from palanteer import *

globalMinValue, globalMaxValue =  0, 10

# Handler (=implementation) of the example CLI, which sets the range
def setBoundsCliHandler(minValue, maxValue):              # 2 parameters (both integer) as declared
    global globalMinValue, globalMaxValue
    if minValue>maxValue:                                 # Case where the CLI execution fails (non null status). The text answer contains some information about it
        return 1, "Minimum value (%d) shall be lower than the maximum value (%d)" % (minValue, maxValue)

    # Modify the state of the program
    globalMinValue, globalMaxValue = minValue, maxValue
    # CLI execution was successful (null status)
    return 0, ""


def main(argv):
    global globalMinValue, globalMaxValue

    plInitAndStart("example")                             # Start the instrumentation
    plDeclareThread("Main")                               # Declare the current thread as "Main", so that it can be identified more easily in the script
    plRegisterCli(setBoundsCliHandler, "config:setRange", "min=int max=int", "Sets the value bounds of the random generator")  # Declare the CLI
    plFreezePoint()                                       # Add a freeze point here to be able to configure the program at a controlled moment

    plBegin("Generate some random values")
    for i in range(100000):
        value = int(globalMinValue + random.random()*(globalMaxValue+1-globalMinValue))
        plData("random data", value)                      # Here are the "useful" values
    plEnd("")                                             # Shortcut for plEnd("Generate some random values")

    plStopAndUninit()                                     # Stop and uninitialize the instrumentation

# Bootstrap
if __name__ == "__main__":
    main(sys.argv)
</details>

Scripting example

Both examples above (C++ and Python) can be remotely controlled with a simple Python script.

Typical usages are:

  • Tests based on stimulation/configuration with CLI and events observation, as data can also be traced
  • Evaluation of the program performance
  • Monitoring
  • ...
<details> <summary> See a scripting example code (Python) </summary>
#! /usr/bin/env python3
import sys
import palanteer_scripting as ps

def main(argv):
    if len(sys.argv)<2:
        print("Error: missing parameters (the program to launch)")
        sys.exit(1)

    # Initialize the scripting module
    ps.initialize_scripting()

    # Enable the freeze mode so that we can safely configure the program once stopped on its freeze point
    ps.program_set_freeze_mode(True)

    # Launch the program under test
    ps.process_launch(sys.argv[1], args=sys.argv[2:])
    # From here, we are connected to the remote program

    # Configure the selection of events to receive
    my_selection = ps.EvtSpec(thread="Main", events=["random data"]) # Thread "Main", only the event "random data"
    ps.data_configure_events(my_selection)

    # Configure the program
    status, response = ps.program_cli("config:setRange min=300 max=500")
    if status!=0:
        print("Error when configuring: %s\nKeeping original settings." % response)

    # Disable the freeze mode so that the program resumes its execution
    ps.program_set_freeze_mode(False)

    # Collect the events as long as the program is alive or we got some events in the last round
    qty, sum_values, min_value, max_value, has_worked = 0, 0, 1e9, 0, True
    while ps.process_is_running() or

Related Skills

View on GitHub
GitHub Stars2.2k
CategoryDevelopment
Updated10h ago
Forks97

Languages

C++

Security Score

85/100

Audited on Mar 30, 2026

No findings