This project aims to build an AI agent that uses the Linux perf tool to automatically:
- Identify performance bottlenecks in a given C++ program.
- Understand the nature of these bottlenecks.
- Propose and apply code modifications to address them.
- Generate multiple variants of the optimized code.
- Test these variants using
perfto verify performance improvements. - Iterate through this process 2-3 times to find the best performing version.
- Log the entire process and its findings.
- Linux environment (as
perfis a Linux tool) - Python (version 3.8+ recommended)
perftool installed (usually available via system package manager, e.g.,sudo apt-get install linux-tools-common linux-tools-generic)- A C++ compiler (e.g.,
g++) - Poetry for dependency management (recommended)
- OpenAI API key (if using LLM-based agents like Analyzer or Replicator), set as an environment variable
OPENAI_API_KEY.
-
Set up the project: Ensure you have the project files on your local system.
-
Install dependencies using Poetry: If you don't have Poetry, install it first (see Poetry documentation). Navigate to the project's root directory in your terminal, then run:
poetry install
This will create a virtual environment and install all necessary packages defined in
pyproject.toml. -
Verify
perfpermissions: Usingperfoften requires specific permissions. You might need to adjustperf_event_paranoidsettings:sudo sh -c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'To make this change permanent, you'd typically modify
/etc/sysctl.conf. Note: Settingperf_event_paranoidto -1 is permissive; understand the security implications for your system. Refer toman perf_event_openfor more details.
The primary way to run the full optimization pipeline is using the Optimizer script.
-
Activate the Poetry virtual environment: Navigate to the project's root directory in your terminal, then run:
poetry shell
-
Prepare your C++ source code and executable: Place your C++ source files (e.g.,
my_program.cpp,utils.h,utils.cpp) in a directory. You will also need the path to the pre-compiled executable that these source files build into. For example, your project structure might look like:my_project/ ├── src/ │ ├── my_program.cpp │ ├── utils.cpp │ └── utils.h └── build/ └── my_app <-- This is your executableThe Optimizer pipe will process
.cpp,.cc,.cxx,.h,.hpp,.hxxfiles found directly in the specified source directory. -
Run the Optimizer pipe: Use the
--source-dirargument for your C++ source files,--executablefor the path to your compiled application, and--output-dirto specify where the results should be saved.poetry run python -m pipe.optimizer.optimizer \ --source-dir my_project/src/ \ --executable my_project/build/my_app \ --output-dir optimizer_run_1This will first run the
Profileron the provided executable and source directory to get a global performance profile. Then, for each C++ source and header file found inmy_project/src/, the Optimizer will:- Analyzer: Combine the file's content with the global profile to identify potential bottlenecks.
- Replicator: Generate code variants to address these bottlenecks.
- Patcher: Write these variants to disk.
- Profiler (per variant): Profile each generated variant in its own directory context.
- Evaluator (per variant): Compare each variant's profile to the original and print if a variant is a "Significant Improvement".
The results and intermediate files will be saved in the
optimizer_run_1directory.
After each iteration, the pipeline prints a summary table of all variants, highlighting the best variant (with the highest improvement percentage). At the end, it prints an overall summary and the best variant across all iterations. -
Running individual agents: Each agent in the
step/directory can also be run individually. Refer to their respectiveREADME.mdfiles (linked in the Directory Structure section) for specific instructions. These typically require a specific input YAML file. For example, to run the Profiler directly (which needs a profiler input YAML):poetry run python -m step.profiler.profiler_agent -o profiler_output.yaml step/profiler/examples/profiler_input.yaml
README.md: This file - an overview of the project.core/: Contains core components, base classes (likeStep), and utilities shared across the project.pipe/: Contains orchestration scripts that combine multiple steps into a pipeline.pipe/optimizer/README.md: Orchestrates an initial global Profiler run, then for each source/header file, runs Analyzer, Replicator, and Patcher.
step/: Contains the different autonomous steps or "agents" that form the profiling and optimization pipeline. Each sub-directory typically represents a distinct stage with its ownREADME.md:step/profiler/README.md: Compiles the code and gathers initialperfdata and reports.step/analyzer/README.md: Analyzesperfreports (potentially using LLMs) to identify bottlenecks.step/replicator/README.md: Proposes and applies code modifications based on analysis.step/evaluator/README.md: Evaluates the performance of modified code variants.step/patcher/README.md: Applies a selected code variant to the original source file.
tool/: Contains Python wrappers and interfaces for external command-line tools used by the steps.tool/compile/: Wrapper for the C++ compiler (e.g.,g++).tool/perf/: Wrapper for the Linuxperftool (handlingrecord,report, etc.).
data/: Contains data generated and used during the process. Subdirectories might include:data/sources/: Input C++ source files.
An extension for this project is the addition of an agent dedicated to automatically fixing compilation issues in generated code variants. Currently, if a code variant fails to compile, it is skipped. In the future, a Compilation Fix Agent could be integrated into the pipeline—particularly during the evaluator phase of the optimizer.
This agent would:
- Detect compilation errors in variant code.
- Attempt to automatically fix these errors (potentially using LLMs or rule-based approaches).
- Re-attempt compilation and, if necessary, iterate this process a configurable number of times to maximize the chances of producing a correct, compilable variant.
Another possible improvement is to merge the Patcher functionality into the Replicator agent. This would streamline the pipeline by having the Replicator not only generate code variants but also directly handle writing these variants to disk, reducing the number of orchestration steps and simplifying data flow between agents.