Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Taking Snapshots of the Call Stack Using Pyinstrument

00:00 In this lesson, you’ll install and use Pyinstrument to profile two functions that work together to find prime numbers in a given range.

00:10 Pyinstrument is a third-party statistical profiler for Python that shows you where your code spends its time across the whole call stack. It gives you a tree of function calls and takes snapshots while your program runs so you can see which functions were active and for how long.

00:30 This is done with less overhead compared to deterministic profilers. Pyinstrument makes it more practical to spot slow parts of your code compared to something like cProfile, which just lists every function called without context.

00:47 To test out Pyinstrument, you have these two functions that help you find prime numbers within the range. The first function is is_prime(). It takes in number as an input and checks whether it’s prime or not.

01:01 First, it returns False if the number is less than two. Then it checks divisibility from 2 up to number - 1. If it does find a divisor, it returns False, and otherwise, it returns True.

01:15 The second function is find_prime_numbers(), which is the main function you run. find_prime_numbers() takes in two inputs: start and end, then it loops from start to end - 1.

01:29 It uses the is_prime() function from before to check whether each number is prime or not. If that number is prime, it appends it to a list and finally, it returns the list of prime numbers.

01:44 Your task is to use Pyinstrument to profile the find_prime_numbers() function and identify where most of the time is being spent when checking for primes between one and a hundred thousand.

02:00 You could use Pyinstrument either in your command line or in a Python file. Here you’re using it in a Python file called py_ instrument_prime.py.

02:09 You already have the is_prime() and find_prime_numbers() functions here. But since pyinstrument is a third-party tool, you’ll need to install it first.

02:20 You can use any package manager like pip, or uv. I’m using pip. pip install pyinstrument

02:32 And as you can see, it says "Requirement already satisfied" because I’ve already installed it before. Usually it’s best to install third-party packages inside the virtual environment to keep your projects isolated and avoid conflicts.

02:47 But I use Pyinstrument all the time, so I’ve installed it globally to keep it handy. To start, you need to import Profiler from pyinstrument.

02:58 from pyinstrument import Profiler with a capital P.

03:06 After your function definitions, you can use Profiler as a context manager. So with Profiler( here you can set the interval parameter, which tells Pyinstrument how often to take a snapshot of the call stack while your program runs.

03:26 For example, setting interval=0.001 means it will take a snapshot every one millisecond. A typical value is between 0.001 and 0.1 seconds depending on how detailed you want the output and how long your program runs.

03:47 And after you close the parenthesis: as profiler:.

03:53 Now you need to run the function you want to profile. In your case, it’s find_prime_

04:02 numbers(1, 100000).

04:07 Okay, now outside the context manager, you can run profiler.print() to actually view the results of the profiler.

04:18 Now head over to the terminal. Let’s clear the output and run this file: python py_instrument_ prime.py.

04:47 Okay, now you can see the report showing you the call hierarchy of functions. Right away, this view is more informative than the default output from cProfile because it shows you the context of each function call.

05:02 This matters because the same function might be called from multiple places for different reasons, and this view helps you see exactly where and how time is being spent.

05:12 Your root function is module, 14.73 seconds was spent here. This is your script’s total runtime. Then you have find_prime_numbers(), 14.73 seconds again.

05:28 So this is all time spent finding primes. And finally, you have is_prime() in line three, this is showing you 14.72 seconds. From this, you can conclude that almost all the time in your script was spent here in is_prime().

05:49 So if you were to optimize the performance of your script, you would have to deal with is_prime().

05:57 So to recap, Pyinstrument is a statistical profiler that takes snapshots of your program’s call stack at regular intervals while it runs. Instead of logging every single function call like cProfile, it samples what’s happening over time, giving you a high-level view of where most of the time is actually being spent.

06:17 You now know how to use Pyinstrument to profile your scripts and how to read the call hierarchy to see exactly where your code is spending time.

Become a Member to join the conversation.