paint-brush
Recording Stack Trace Methods and Their Analysis With Profilerby@leonidivankin
581 reads
581 reads

Recording Stack Trace Methods and Their Analysis With Profiler

by Leonid IvankinSeptember 26th, 2022
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

The Profiler is one of the most powerful tools in Android Studio. It allows you to look inside a running application to detect problems. It is integrated into Android Studio and can be easily easily accessed by clicking a button 50 times. The last method will stop the thread for 2000 ms. The point of this example is to clearly see how Profiler works, specifically the stack of methods it calls, how long they take and what effect they have on the processor. After launching, you may see a pretty deep (50 pieces) and pretty wide (2000ms) stack.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Recording Stack Trace Methods and Their Analysis With Profiler
Leonid Ivankin HackerNoon profile picture

Introduction

Profiler is one of the most powerful tools in Android Studio, but it has a rather high entry threshold. It allows you to look inside a running application to detect problems. Profiler is integrated into Android Studio.


Working with Profiler

Let's take Profiler as an example of ProfilerActivity. Full code here:


class ProfilerActivity : AppCompatActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           Button(onClick = { countNumber(50) }) {
               Text("Perform methods")
           }
       }
   }

   private fun countNumber(number: Int) {
       if (number == 0) {
           Thread.sleep(2000)
           return
       }
       countNumber(number - 1)
   }
}


After launching, you may see the following:



The point of this example is to clearly see how Profiler works, specifically the stack of methods it calls, how long they take and what effect they have on the processor. To do this, there is a button, when you click it 50 times, the countNumber() method will be executed. The last method will stop the thread for 2000 ms. There is no business logic in this. This is just to show how the Profiler works. So, we should see a pretty deep (50 pieces) and pretty wide (2000ms) stack of methods.


Create a ProfilerActivity and copy all the code into it. Note that this example uses jetpack compose. So don't forget to include it in the project. Run ProfilerActivity.


In order to use the Profiler, just go to the tab below:



Then click on the plus sign and select the desired device and application process:


After selecting the desired application process, it will start monitoring it:



The number 6 (see picture above) marks the application process being monitored.


The number 1 marks the activation currently in use.


In line 2 you can monitor the CPU activity.


Line 3 is the RAM usage.


Line 4, as you can see, is not active. This was where you could track sending and receiving requests from the network. But it has moved to a separate Network Inspector tab, as you can see from the message marked with the number 7.


Line 5 is where you can track your battery usage.


In fact, to dive into each of these items, you need to read quite a bit of documentation and articles. In this piece, we will look at the most commonly used and at the same time difficult to enter - CPU monitoring (point 2).


Let's click on the CPU line.


After clicking we went to the tab monitoring only the processor (point 1, see picture above). You can always go back by clicking on the arrow (point 4). Now let's try to see the stack of methods running in the application. To do this, select Java/Kotlin Method Trace Recording (point 2) and select Record (point 3). After that, the recording starts. Press Perform methods button in the application and then press the stop button on the recording (point 5).


The recording has stopped and the window for analyzing the recorded method stack has opened:


If you have done everything correctly, you will see a picture similar to mine.


In it you can see:

-the pink dot (point 1) - the moment of interaction with the application (pressing the button);

-the threads participating in the application (point 2);

-the main thread of the application (item 3), where the visual components are rendered;

-the executed method stack ( point 4).


Click on the arrow next to the stream name and scroll down to reveal the stream and see the details:

A column of green and blue lines like this will appear. Notice that you can see the name of the ProfilerActivity.countNumber and Thread.sleepmethod:


If you click on any line, you can find out about the execution of this method, in particular, the total execution time is 2s (2000 ms), which is true:


You can also change the scale of the timeline and navigate through it:

Mac: Command+Scroll

Windows: A, S, D, W



The method described above searches the application for problems, usually the longest lines, and then analyzes what caused them. These problems are then eliminated.


Finding and eliminating the fault

Let's change the application code a little bit:


class ProfilerActivity : AppCompatActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           Button(onClick = {
               sleep100()
               sleep100()
               sleep2000()
               sleep100()
           }) {
               Text("Perform methods")
           }
       }
   }

   private fun sleep100() {
       Thread.sleep(100)
   }

   private fun sleep2000() {
       Thread.sleep(2000)
   }
}


Suppose we have a long-running application but don't understand what's wrong. Let's run it and record a stack trace, as described earlier:



In the picture, you can clearly see that there is a bar that is much longer than the others. It runs for 2000ms and refers to the ProfilerActivity.sleep2000 method. We go to Android Studio and make sure that the method stops at 2000ms:


Next, we can take the following actions:

-or move execution to the background thread/coroutine;

- or start digging further into the code of this method to understand what causes it to take so long to execute and whether it should.


By and large, this is the essence of working with Profiler CPU. There are more detailed descriptions of methods here, you can write a C++ method stack, and adjust the sampling rate, but the gist is the same. You can read more here.


Conclusion

The Profiler is a pretty powerful tool that lets you analyze an application at runtime and look for problems in it. You won't need it 95% of the time when you're working on a project. But in the remaining 5% you can't do without it. It's also worth mentioning that Profiler is well integrated with Android Studio, which makes it not only powerful but also incredibly handy compared to other similar tools like Perfetto.