## User Manual: Python Profile Analyzer (English) ### 1. Introduction Welcome to the Python Profile Analyzer! This tool is designed to answer one of the most common questions in software development: "Why is my code slow?" Python Profile Analyzer allows you to run your code under Python's standard profiler, `cProfile`, and analyze the results through an intuitive graphical interface. Instead of parsing complex text files, you can navigate the data, sort, filter, and visualize the interactions between functions to quickly identify bottlenecks and optimize your application's performance. ### 2. Interface Overview The interface is divided into three main areas: 1. **Top Toolbar**: * **Load Profile File...**: Loads a pre-existing profiling data file (`.prof`). * **Profile a Script...**: Opens the Launch Profile Manager to configure and run the profiler on a new script or module. * **Export to CSV...**: Exports the data currently displayed in the table to a CSV file. * **Current Profile**: Displays the name of the currently loaded profile file. 2. **Main Statistics Panel**: * This is a tabbed area that provides different views of the data: * **Table View**: The primary view. An interactive table with statistics for each function. * **Text View**: The standard text output from `pstats`, useful for a classic overview. * **Graph View**: (Available only if Graphviz is installed) A call graph visualization. * **Controls (below the tabs)**: Allow you to sort and filter the data displayed in the table and text views. 3. **Details Panel (at the bottom)**: * When you select a function in the **Table View**, these two panels are automatically populated: * **Callers**: Shows which functions called the selected function. * **Callees**: Shows which functions were called by the selected function. ### 3. Core Workflows #### A. Profiling a New Script This is the most common way to get started. 1. Click **"Profile a Script..."**. This will open the "Launch Profile Manager" window. 2. Click **"New"** to create a new profile. 3. **Fill in the profile details**: * **Profile Name**: A descriptive name (e.g., "My Test Script"). * **Run as Module**: Check this option if you want to launch a module (e.g., `python -m my_module`). * **Script Path** (if not a module): Click `...` to select the `.py` file to run. * **Project Root Folder** (if running as a module): Click `...` to select your project's root folder. * **Module Name** (if running as a module): Enter the name of the module to launch (e.g., `my_module.main`). * **Arguments**: Enter any arguments to pass to the script (e.g., `--input file.txt --verbose`). 4. Click **"Save Changes"**. 5. Your new profile will appear in the list on the left. Select it and click **"Run & Profile Selected"**. 6. The application will run your script in the background. When it's finished, the results will be automatically loaded and displayed. #### B. Loading an Existing Profile File If you already have a data file (`.prof`) generated previously (even from the command-line `cProfile`), you can analyze it. 1. Click **"Load Profile File..."**. 2. Select your `.prof` file from the dialog box. 3. The data will be loaded and displayed in the interface. ### 4. Analyzing Results: A Use Case Understanding the data is key. Let's imagine we have the following script, `slow_script.py`, to analyze: ```python # slow_script.py import time def utility_function(n): # A fast function, but called many times return n * 2 def expensive_calculation(): # An intrinsically slow function print("Doing expensive calculation...") time.sleep(2) # Simulate a heavy computation print("...done.") def process_data(): # A function that orchestrates other calls print("Processing data...") total = 0 for i in range(1000): total += utility_function(i) expensive_calculation() print(f"Final total: {total}") if __name__ == "__main__": process_data() ``` After profiling this script, here is how to interpret the results. #### Step 1: What is the single slowest function? Go to the **Table View** and click the **"Total Time (s)"** column header to sort in descending order. * **What to look for**: The function at the top of the list. `Total Time` (or `tottime`) is the time spent *inside* a function, excluding time spent in functions it calls. * **Expected Result**: You will see `time.sleep` or a similar function at the top, with a `tottime` of about 2 seconds. Right after it, you'll see `expensive_calculation`, but with a very low `tottime`, because almost all of its time was spent in `time.sleep`. This tells you that `expensive_calculation` is slow due to a specific operation within it. #### Step 2: Which function is a bottleneck because of the functions it calls? Now, sort by **"Cum. Time (s)"** (Cumulative Time). * **What to look for**: `Cumulative Time` (or `cumtime`) is the total time spent in a function, *including* the time spent in all sub-calls. It's useful for finding "manager" functions that are slow because of the work they delegate. * **Expected Result**: `process_data` will be at the top of the list with a `cumtime` of just over 2 seconds. Its `tottime` will be low, but the high `cumtime` tells us it's the starting point of our bottleneck. #### Step 3: Is there a function that is called too many times? Sort by **"N-Calls"** (Number of Calls). * **What to look for**: Functions with an exceptionally high call count. Even a fast function, if called millions of times, can cause a slowdown due to overhead. * **Expected Result**: `utility_function` will appear at the top with 1000 calls. By selecting it, you'll see its `tottime` and `cumtime` are very low, so in this case, it's not a problem. But if they were significant, you would have found a candidate for optimization (e.g., vectorization). #### Step 4: How can I visualize the execution flow? Switch to the **Graph View** tab. * **What to look for**: The "hot path." The nodes (functions) are colored from green (fast) to red (slow) based on their `tottime`. The arrows indicate the call flow. * **Expected Result**: You will see a path from `process_data` to `expensive_calculation`, and from there to `time.sleep`. The `time.sleep` node will be bright red, clearly indicating it's the source of the slowdown. You will also see an arrow from `process_data` to `utility_function` with the label "1000 calls". * **Tip**: Use the **"Node Threshold"** slider to filter out insignificant functions and reduce noise in complex graphs. #### Step 5: Who calls this slow function, and what does it call? Return to the **Table View** and select the row for `expensive_calculation`. * **Look at the Callers panel**: You will see that it was called by `process_data`. * **Look at the Callees panel**: You will see that it called `time.sleep`. This confirms the call context, helping you understand where and why a function is executed. ### 5. Troubleshooting * **The "Graph View" is disabled or gray**: 1. Ensure you have installed the **Graphviz** software (not just the Python library). 2. Ensure that the Graphviz `bin` folder is in your system's `PATH`. 3. Ensure you have installed the `Pillow` library (`pip install Pillow`). 4. After loading a profile, an initial graph is generated automatically. If you don't see anything, try clicking "Generate Graph" or reducing the threshold.