Long-running applications are not always busy doing work. In the case of, for instance, web, serverless or microservice applications, the work is done on every request, and the processes are idle the rest of the time. Similarly, if the program is processing messages from the queue, it may be idle when it is waiting for messages.
A reference to an object, if not properly managed, may be left assigned even if unused. This usually happens on an application logic level but can also be an issue inside of an imported package.
There are multiple reasons why a program will consume more CPU resources than excepted. For a highly computationally complex algorithm, the amount of data it operates on will drive the CPU usage. For I/O-intensive programs, data processing may be the bottleneck. Garbage collection activity is another usual suspect.
Performance profiling is essential for optimizing and fixing an application’s resource consumption, response time and failures. A performance issue without an execution profile is like an error without a stack trace. It will lead to a lot of manual work to get to the root cause.
The difference between a program’s exponential, linear, logarithmic and constant execution times is critical for various use cases. Even if an algorithm is purposely designed to satisfy a certain complexity class, there are multiple reasons why it might not. An underlying library, OS or even hardware can be the root cause of a performance problem.