When starting with optimization work, it is important to work using a workflow similar to test-driven development rather than running some manual tests continuously. A good practice is to dedicate a test module in the application, with test functions that use code components that have to be optimized. Using this approach will help you track your progress while you are optimizing the application.
You can even write a few assertions where you set some speed objectives. To prevent speed regression, these tests can be left after the code has been optimized. Of course, measuring the execution time depends on the power of the CPU used, so it is extremely hard to collect objective measurement in a repeatable way on every environment. This is why speed tests are done best if they are executed on a carefully prepared and isolated environment. It is also crucial to make sure that only one speed test is done at a time. It is also better to concentrate on observing performance trends rather than on using hardcoded time limit assertions. Fortunately, many popular testing frameworks like pytest and nose have available plugins that can automatically measure test execution time and even compare the results of multiple test runs.
Let's take a look at finding bottlenecks in the next section.