Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement fast dump #2047 #2121

Closed
wants to merge 9 commits into from
Closed

Implement fast dump #2047 #2121

wants to merge 9 commits into from

Conversation

alhah
Copy link

@alhah alhah commented May 5, 2021

All you need to do is to add the dependency of ‘fast-dump’, 'DumpWrapper' will automatically do the rest.
Support Android 5~11.

Signed-off-by: xueqiushi xueqiushi@kuaishou.com

@CLAassistant
Copy link

CLAassistant commented May 5, 2021

CLA assistant check
All committers have signed the CLA.

All you need to do is to add the dependency of ‘fast-dump’, 'DumpWrapper' will automatically do the rest.
Support Android 5~11.

Signed-off-by: xueqiushi <xueqiushi@kuaishou.com>
@pyricau
Copy link
Member

pyricau commented May 11, 2021

Nit: can you rename the top folder and artifact name from fast-dump to android-fast-dump? Just to make it clear this is an Android specific artifact.

fast-dump/build.gradle Outdated Show resolved Hide resolved
fast-dump/gradle.properties Outdated Show resolved Hide resolved
fast-dump/src/main/AndroidManifest.xml Outdated Show resolved Hide resolved
fast-dump/src/main/cpp/klog.h Outdated Show resolved Hide resolved
try {
System.loadLibrary("fast-dump")
} catch (e: UnsatisfiedLinkError ) {
e.printStackTrace()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally there should probably an explicit load method, maybe with a boolean indicating whether loading was successfull. Then the consumer can check that before calling forkDumpHprof

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would make the reflection calls a bit more cumbersome, but also allows to fallback to default if it didn't work.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check & fallback implements in DumpWrapper.dumpHprofData with InvocationTargetException

leakcanary-android-utils/build.gradle Outdated Show resolved Hide resolved
@Throws(IOException::class)
fun dumpHprofData(fileName: String) {
if (isSupportFastDump()) {
checkNotMainThread()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is not main thread important?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forkDumpHprof is a synchronous call,it use waitpid to wait child process to complete dump hprof, and then shark can analyze it. If someone call it in main thread, it will block the user.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. The trick is, this is currently exposed as an API on the LeakCanary object so someone might call it from the main thread. I'm not sure what to do, if we should enforce that at the callsite, switch off to a background thread, or just not use fast dump if called from the main thread.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think fallback in main thread called situation is better. If someone does not realize that fast dump should be called in a background thread, it is hardly for him to use fast dump correctly.
Switch off to a background thread automatically would make someone confused.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. So what you're saying is that with "fast dump" the dumping isn't faster, but it's non blocking which means the parent process can keep running while the dump is happening in a child process, so it doesn't make sense to wait for that on the main thread and block. And in that case we might as well use the default API. Ok I like it.

try {
fastDumpClass?.getDeclaredMethod("forkDumpHprof", String::class.java)?.invoke(null, fileName)
} catch (e: Exception) {
e.printStackTrace()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exception do you expect here? We should be specific, and handler better than with default logging. Can you use SharkLog ?

Also the fallback on failure should be just Debug.dumpHprofData no?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Load library fail or something unexpected,add a fallback is a good idea.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to forkDumpHprofMethod


private val fastDumpClass by lazy {
try {
return@lazy Class.forName("com.squareup.leakcanary.FastDump")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this is good, it means fast dump is optional and you have to specifically include the artifact to get it.

alhah added 2 commits May 12, 2021 07:54
Rename the top folder and artifact name from 'fast-dump' to 'android-fast-dump'

Signed-off-by: xueqiushi <xueqiushi@kuaishou.com>
Signed-off-by: xueqiushi <xueqiushi@kuaishou.com>
Copy link

@sstallion sstallion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution @alhah! I'm excited to see native code being contributed to Leak Canary, but since this is the first PR to do so there might be a little more work to get this merged.

In general, your changes look good but I would like to see your CMake list files updated with some additional warning/error checks. Also, would it be possible to update your code to reflect the conventions documented in Google's C++ style guide (See https://google.github.io/styleguide/cppguide.html)?

Thanks again for the hard work!

alhah added 3 commits May 13, 2021 20:36
Signed-off-by: xueqiushi <xueqiushi@kuaishou.com>
Signed-off-by: xueqiushi <xueqiushi@kuaishou.com>
Signed-off-by: xueqiushi <xueqiushi@kuaishou.com>
@alhah
Copy link
Author

alhah commented Jun 29, 2021

Is there any other problem? @sstallion

@pyricau
Copy link
Member

pyricau commented Jun 29, 2021

I do want to merge this but I'm on paternity leave so not working at the moment.

@alhah
Copy link
Author

alhah commented Jun 29, 2021

Congratulations, have a good holiday.

@pyricau
Copy link
Member

pyricau commented Sep 16, 2021

I started looking more closely, playing with it and adding a few minor changes.

One thing I'm curious about: when I tried to push to an x86 emulator, of course we don't have a native fast dump lib for it. How can we configure the library so that it's a no-op on non supported architectures, without adb outputting an error:

Execution failed for task ‘:leakcanary-android-sample:installDebug’.
java.util.concurrent.ExecutionException: com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113

1. Support x86/x86_64 for emulator.
2. Optimize symbol search performance & reliability, support symbol in .gnu_debugdata.
3. Android R fast dump uses another implementation, which is consistent with the lower version.
4. Use c++17 instead of c++11 for make_unique.
5. Workaround for NDK bug: android/ndk#721

Signed-off-by: xueqiushi <xueqiushi@kuaishou.com>
@alhah
Copy link
Author

alhah commented Sep 20, 2021

I started looking more closely, playing with it and adding a few minor changes.

One thing I'm curious about: when I tried to push to an x86 emulator, of course we don't have a native fast dump lib for it. How can we configure the library so that it's a no-op on non supported architectures, without adb outputting an error:

Execution failed for task ‘:leakcanary-android-sample:installDebug’.
java.util.concurrent.ExecutionException: com.android.builder.testing.api.DeviceException: com.android.ddmlib.InstallException: INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113

Support x86/x86_64 for emulator and do some optimization
  • Android R fast dump uses another implementation, which is consistent with the lower version.
  • "lzma" is a library copied from AOSP to decompress symbol data in ”.gnu_debugdata", so the compile warnings were not handled.

@alhah
Copy link
Author

alhah commented Dec 22, 2021

For example, dlsym(handle, "xxx") in kwai_dlfcn need to search xxx.so, the information of these symbols are stored in different sections, such as .dynsym, .symtab. However, in the high version of the android system, in order to reduce the library size, the information of the .symtab section will be compressed with 7z and saved in the .gnu_debugdata section when compiling, so it is necessary to decompress it first when searching for symbols.

@pyricau
Copy link
Member

pyricau commented Dec 22, 2021

Thanks!

This PR has a ton of code, and I'm not familiar with the intricacies of C. However, I do want to enable LeakCanary to benefit from these speedups.

As a first step, I'm creating an API to customize the heap dumper in #2237

That way you'll be able to do something like:

LeakCanary.config = LeakCanary.config.copy(
  heapDumper = HeapDumper {
    DumpWrapper.dumpHprofData(it.absolutePath)
  }
}

@pyricau
Copy link
Member

pyricau commented Jan 10, 2022

@alhah hi! With LeakCanary 2.8, it's now possible to customize the heap dumper.

I'm really sorry this PR has been open for so long. It's really hard for me to review it as I'm not comfortable with native code. It would be even harder for me to maintain it in the future, so merging this PR also means increased maintenance burden and higher risk.

I was thinking, an alternate path here would be for you to create your own repo (e.g. android-fast-dump), upload artifacts on maven central directly, and then we can add instructions in the docs on how to use it with LeakCanary?

@alhah
Copy link
Author

alhah commented Jan 11, 2022

That's OK, it's not hard for me, I can integrate KOOM into the custom dumper.

@pyricau
Copy link
Member

pyricau commented Apr 2, 2022

@alhah Thanks! Do you want to document somewhere (maybe on a Readme in KOOM) how to integrate the two things together? Then I can add a link from the LeakCanary docs to the Koom readme that explains how to use KOOM's heap dump for LeakCanary?

@pyricau pyricau closed this Apr 2, 2022
@alhah
Copy link
Author

alhah commented Apr 6, 2022

We are preparing a new version of KOOM, providing an API to support custom dumper.

@alhah
Copy link
Author

alhah commented May 3, 2022

We just released 2.1.0 to support custom fork dumper, I tried to integrate it into leakcanary, it works, but the code is not very elegant, I will optimize it and release a new version soon.

Here is the patch for test.
forkdump.txt

Here is the logcat, 6757 is the main process id and 6800 is the child process id.

05-03 20:35:08.614 10137  6757  6785 I OOMMonitor_ForkJvmHeapDumper: dump /storage/emulated/0/Download/leakcanary-com.example.leakcanary/2022-05-03_20-35-08_216.hprof
05-03 20:35:08.614 10137  6757  6785 I OOMMonitor_ForkJvmHeapDumper: before suspend and fork.

05-03 20:35:08.620 10137  6800  6800 I mple.leakcanar: hprof: heap dump "/storage/emulated/0/Download/leakcanary-com.example.leakcanary/2022-05-03_20-35-08_216.hprof" starting...
05-03 20:35:10.011 10137  6800  6800 I mple.leakcanar: hprof: heap dump completed (23MB) in 1.390s objects 324186 objects with stack traces 0
05-03 20:35:10.110 10137  6800  6800 I JNIBridge: process 6800 will exit!

05-03 20:35:10.117 10137  6757  6785 I OOMMonitor_ForkJvmHeapDumper: notify from pid 6800

@pyricau
Copy link
Member

pyricau commented May 3, 2022

Very cool! When you have the new release, can you open an issue with the setup steps and I'll add it to the documentation?

@alhah
Copy link
Author

alhah commented May 4, 2022

Sure.

@alhah
Copy link
Author

alhah commented May 23, 2022

Very cool! When you have the new release, can you open an issue with the setup steps and I'll add it to the documentation?

Done in #2387. @pyricau

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants