preface

The process of performance optimization is divided into two parts: 1. Discovering performance bottlenecks 2

Solutions to performance problems need to be analyzed on a case-by-case basis. There is no fixed way, but more accumulation of experience, which is not involved in this paper. But there is a certain way to find performance bottlenecks. This article focuses on finding performance bottlenecks.

How do I find performance bottlenecks

A commonly used performance monitoring tool is TraceView, which is integrated in the Android Device Monitor. Starting with Android Studio3.0, the Android Device Monitor was scrapped in favor of the Android Profiler, Memory Prodiler, CPU Profiler and Network Prodiler are provided.

Memory optimizations (including Memory leaks) are commonly used by MAT or LeakCanary, and Memory Profiler is equivalent to integrating a simplified version of MAT’s functionality into AS. In terms of performance optimization, CPU Profiler is equivalent to integrating traceView functionality into AS. So, if you’re using AS3.0 before, you can use TraceView, and if you’re using AS3.0 after, you can also use a CPU Profiler. You can use Systrace if you want to track detailed system progress data to solve problems such as frame lag, which is not covered in this article.

##### read the full text at the end of the free advanced Android learning materials and high-definition thinking brain map!

Traceview usage

To use traceView, you need to first use the Debug class for staking. When the application executes the code to be staked, the.trace file will be automatically generated in the sdcard of the mobile phone. After that, you can use TraceView or AS (version 3.0 or above) to open the file.

A, the pile

Peg will use the Debug class and will generate.trace files in sdcard, so you must first ensure that your application has WRITE_EXTERNAL_STORAGE permission.

Peg at the beginning and end of the code logic you want to track:

// Starts recording a trace log with the name you provide. For example, the
// following code tells the system to start recording a .trace file to the
// device with the name "sample.trace".Debug.startMethodTracing("sample"); . // The system begins buffering the generated trace data, until your // application calls stopMethodTracing(), atwhich time it writes
// the buffered data to the output file.Debug.stopMethodTracing();
Copy the code

The resulting.trace file is saved in the same fixed directory as the one returned by getExternalFilesDir(), that is, /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files. Note that if your application calls startMethodTracing() again without changing the trace log name, existing logs saved to the device will be overwritten. If you want to save each run to a different log file, you can use the following code:

// Uses the SimpleDateFormat class to create a String with
// the current date and time.SimpleDateFormat date =
        new SimpleDateFormat("dd_MM_yyyy_hh_mm_ss");
String logDate = date.format(new Date());
// Applies the date and time to the name of the trace log.Debug.startMethodTracing(
        "sample-" + logDate);
Copy the code

If the system reaches the maximum cache value before you call stopMethodTracing(), the trace stops and a notification is sent to the manager. The functions that start and stop tracing are valid throughout your application flow. That is, you can add onCreate(Bundle) to your Activity

StartMethodTracing () is called in the function, and stopMethodTracing() is called in the Activity’s onDestroy() function.

Check the.trace file

Once the stakes are in place, install the application and run the functions of the detected parts, and then you can view the files through AS or TraceView.

Use AS to view

Android File Explorer: View-tool Windows-Android File Explorer

The generated.trace file can be found under /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files. Double-click the file to open it.

Save the.trace file to your computer and drag it directly into the AS window, or open the view directly.

In the view that opens, you can select the thread you want to view in the upper left. You can see how long a specified thread ran during monitoring, which methods were executed, how long each method was executed, and so on.

There are four nouns that need explaining:

  • Wall Clock Time: indicates the actual elapsed Time, i.e. the Time between entering a method and exiting the method, regardless of whether the thread is active or dormant.

  • Thread Time: indicates the actual elapsed time minus the amount of time that the Thread does not consume CPU resources (in hibernation). For any given function, the thread time is always less than or equal to its wall clock time. Using thread time gives you a better idea of how much of the actual CPU usage of a thread is consumed by a given function.

  • Inclusive Time: the Time a method spends executing its own code + the Time it spends executing its own child method.

  • Exclusive Time: The Time at which a method executes its own code.

Use TraceView to view

To use traceView, first save the.trace file to your computer:

adb pull /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files/sample.trace D:\Documents\sample.trace
Copy the code

Start the Android Device Monitor. Before AS3.0, this is the window where LogCat is located, and then switch to the TAB page. After AS3.0, go to the android-sdk/tools/ directory and run the following command:

monitor
Copy the code

Although the DDMS of Android Device Monitor also has File Explorer, mobile phones without root cannot view the above path. Therefore, you can only save the.trace File to the PC for viewing.

In Android Device Monitor, click file-open File successively and select.trace File path to Open:

The content is similar to that when AS is opened, but the difference is mainly the icon part, which is not AS intuitive AS the Call Chart of AS.

There are also four concepts:

1.Cpu Time: equivalent to Thread Time in AS. 2.Real Time is the Wall Clock Time. E.g. < 1 > This is not an Inclusive Time. 4.Exclusive Time: same AS AS.

Use AS or TraceView

This is a matter of opinion, according to my personal feeling, I suggest using AS to view. There are two reasons:

AS is simpler. There is no need to open ADM separately, let alone save the.trace file to your computer.

The AS Call Chart is more intuitive, showing the CONSUMPTION of CPU time at a glance.

The horizontal axis of the Call Chart shows when and when a function is called (or called by), and it shows who is called along the vertical axis. The following figure shows an example of an invocation diagram and depicts the concepts of self time, children Time, and total time for a given function.

Finally, it is important to note that the application will slow down during the tracing analysis process. Therefore, the analysis data obtained through TraceView cannot accurately reflect the absolute time when a certain method is actually executed. More on this in the final note.

Google also provides a sample-based analysis approach to reduce the impact of analysis on runtime performance. To enable the sample analysis, need to call the Debug. StartMethodTracingSampling () method (rather than the Debug. StartMethodTracing () method). Samples are collected periodically until stopMethodTracing() is called.

CPU Profiler usage

Function tracing using CPU profilers is simpler than traceView. There is no need to do any code migration, so here is a brief introduction:

First of all, through

View-tool Windows-Android Profiler Opens Android Profiler. After the phone connects to the computer and runs the application, you will see the following view in the Android Profiler:

You can select devices and processes in the upper left corner and click on the CPU area to enter the CPU Profiler view:

Trace mode can be selected in the upper left corner:

**Sampled: ** Captures the application call stack at the default sampling rate. The inherent problem with this pattern is that if the application enters a function after one capture and exits before the next, the analyzer does not record the function call. If you are interested in such a tracing function with a short lifetime, you can use “Instrumented” tracing.

Instrumented: ** To log the timestamp at the start and end of each function call. Analyze and compare timestamps to generate function trace data. It is important to note that setting the overhead associated with a function can affect runtime performance and even analyze data, especially for functions with a relatively short lifetime. In addition, if an application executes a large number of functions in a short period of time, the analyzer can quickly exceed its file size limit and cannot record any more trace data.

**Edit Configurations: ** Custom sample rate. Is similar with the Debug of traceview. StartMethodTracingSampling ().

The.trace file size is limited. For a given recording, when the analyzer reaches this limit, the AS stops collecting new data (however, this does not stop recording). This usually happens more quickly when performing “Instrumented” traces because more data is collected in a shorter period of time than when performing “Sampled” traces.

If you are using an Android 8.0 (API 26) or later device, there is no limit on the file size of trace data, and this value can be ignored. However, you still need to be careful how much data the device collects after each record, AS it may be difficult to parse large trace files.

Click the “Start recording” button at the top, then perform the tracked function in the application, and click the “Stop recording” button when finished. The CPU Profiler automatically starts analyzing and generating data.

That’s how CPU Profiler and TraceView are used. As for how to formulate the optimization plan, it is not launched, and there is no completely fixed way. In my case, the onRebuild() method parallelizes the time-consuming Contact build process, dividing hundreds of ordered builds into five threads for concurrent execution, and then sequentially merging data into one thread. The onRebuild() execution speed eventually increased from 15 seconds to 2.5 seconds, which was enough for me.

Important Notes

Whether using traceView or CPU Profiler for function tracing, it is important to note that the application can slow down during tracing analysis. Therefore, analyzing data does not accurately reflect the absolute time that a method actually takes to execute. Here are four sets of data I recorded while optimizing the onRebuild(Boolean) method in the project. Let’s compare them:

** Actual execution time: ** Actual execution time obtained by printing logs when analysis mode is not enabled. **Profiler count time: ** Execution time obtained using CPU Profiler analysis. ** TraceView count time: ** The execution time obtained by analyzing the.trace file generated by traceView. ** TraceView Actual time: ** The actual execution time obtained by printing logs when traceView is used.

Why are there two times for TraceView? This is because during the test, it was found that the time automatically analyzed by TraceView was not slower than the actual execution time, but much faster. Confused, I calculated the actual execution time by using the following code when TraceView was enabled, which was really slower than the actual execution time.

Debug.startMethodTracing("smssdk_onrebuild");
long curr = System.currentTimeMillis();
onRebuild(true);
Log.d(TAG, "onRebuild lasts: " + (System.currentTimeMillis() - curr));
Debug.stopMethodTracing();
Copy the code

As can be seen from the above table, neither CPU Profiler nor TraceView can accurately represent the actual execution time. What’s more, the data automatically analyzed by TraceView is significantly different from the actual time in traceView tracking mode. I haven’t found a detailed explanation for this. If anyone knows, please kindly comment. Since the time obtained by tracking analysis cannot represent the actual time, is this data useless? Of course not! They are valuable in at least two ways:

  • In the data obtained by one detection, the proportion of the execution time consumed by each method in the whole thread execution time has certain reference value. The method with high proportion should be the key objective of optimization.

  • The data obtained from the two tests before and after optimization are of comparative value to confirm whether the optimization scheme is really effective.

Tracing functions through these tools can only make a relative reference, and cannot fully reflect the performance of the function. For example, the analysis data of onRebuild() method I obtained through CPU Profiler shows that the Contact constructor accounts for about 60% and the contact.tostring () method accounts for about 40% in the whole execution process. But in fact, of the 15 seconds onRebuild() takes, contact.tostring () only takes 100 milliseconds, while more than 90% of that time is consumed by its constructor, The CPU Profiler monitoring process has a greater impact on the performance of contact.tostring ().

However, the same problem did not appear in the analysis results of TraceView.

Note that CPU Profiler and TraceView cannot be used at the same time, and if code for staking is embedded in the code, the CPU Profiler may not be able to start or stop recording properly.

Traceview vs. CPU Profiler

In terms of usage, TraceView is slightly more complex than CPU Profiler. Just like MAT needs to get the.hprof heap dump file first, TraceView also needs to get the.trace file first, and then use TraceView to analyze the file. CPU profilers can analyze applications directly.

The resulting charts, such as the Call Chart and Flame Chart, can be used to visually show which functions are executed in the thread, their execution times, Call stacks, etc. When you right-click on any function, You can jump directly to the corresponding code, which is very convenient and superior to TraceView in this respect.

I Java development 4 years Android development 5 years, regularly share Android advanced technology and experience to share, welcome to pay attention to ~

If you like an article, give it a thumbs up