Skip to content

Commit

Permalink
doc add new chapter "Performance Optimization"
Browse files Browse the repository at this point in the history
  • Loading branch information
teble committed Dec 12, 2023
1 parent fb372dc commit 271a2fa
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 5 deletions.
13 changes: 8 additions & 5 deletions doc-source/src/.vuepress/configs/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ const navigationLinks = {
'/guide/knowledge',
'/guide/quick-start',
'/guide/example',
'/guide/performance-optimization.md',
'/guide/structural-zoom-table',
'/guide/run-on-desktop'
'/guide/run-on-desktop',
],
about: [
'/about/contacts',
Expand Down Expand Up @@ -53,8 +54,9 @@ export const navBarItems = {
{ text: 'Basic Knowledge', link: i18n.string(navigationLinks.start[1], 'en') },
{ text: 'Quick Start', link: i18n.string(navigationLinks.start[2], 'en') },
{ text: 'Usage Example', link: i18n.string(navigationLinks.start[3], 'en') },
{ text: 'Structural Zoom Table', link: i18n.string(navigationLinks.start[4], 'en') },
{ text: 'Run on Desktop', link: i18n.string(navigationLinks.start[5], 'en') },
{ text: 'Performance optimization', link: i18n.string(navigationLinks.start[4], 'en') },
{ text: 'Structural Zoom Table', link: i18n.string(navigationLinks.start[5], 'en') },
{ text: 'Run on Desktop', link: i18n.string(navigationLinks.start[6], 'en') },
]
}, {
text: 'About',
Expand All @@ -73,8 +75,9 @@ export const navBarItems = {
{ text: '基础知识', link: i18n.string(navigationLinks.start[1], 'zh-cn') },
{ text: '快速开始', link: i18n.string(navigationLinks.start[2], 'zh-cn') },
{ text: '用法示例', link: i18n.string(navigationLinks.start[3], 'zh-cn') },
{ text: '结构速查表', link: i18n.string(navigationLinks.start[4], 'zh-cn') },
{ text: '桌面平台运行', link: i18n.string(navigationLinks.start[5], 'zh-cn') },
{ text: '性能优化', link: i18n.string(navigationLinks.start[4], 'zh-cn') },
{ text: '结构速查表', link: i18n.string(navigationLinks.start[5], 'zh-cn') },
{ text: '桌面平台运行', link: i18n.string(navigationLinks.start[6], 'zh-cn') },
]
}, {
text: '关于',
Expand Down
76 changes: 76 additions & 0 deletions doc-source/src/en/guide/performance-optimization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Performance Optimization

In DexKit, various queries may achieve the same functionality, but the difference in performance can
be significant, varying by several tens of times. This section will introduce some techniques for
performance optimization.

At the native layer, DexKit maintains lists of classes, methods, and fields in the Dex file. How
does DexKit scan these lists in several APIs? The traversal order of `findClass`, `findMethod`, and
`findField` is based on the respective lists' sequential order. Then, each condition is matched one
by one.

## declaredClass condition is too heavy

Some users may use the `declaredClass` condition to write queries like the following when using:

```kotlin
private fun badCode(bridge: DexKitBridge) {
bridge.findMethod {
matcher {
declaredClass {
usingStrings("getUid", "", "_event")
}
modifiers = Modifier.PUBLIC or Modifier.STATIC
returnType = "long"
addInvoke {
name = "parseLong"
}
addInvoke {
name = "toString"
}
}
}.single().let {
println(it)
}
}
```

This search takes `4310ms`.

At first glance, this query seems fine, but in reality, its performance is very poor. Why? As
mentioned earlier, the `findMethod` API traverses all methods and then matches each condition one by
one. However, there is a many-to-one relationship between methods and classes, meaning a class may
contain multiple methods, but a method can only belong to one class. Therefore, during the process
of traversing all methods, each method will be matched once with the `declaredClass` condition,
leading to performance waste.

So, let's change our approach. By first searching for `declaredClass` and then using chain calls, we
can search for methods within the classes that meet the criteria. Won't this help avoid the issue?

```kotlin
private fun goodCode(bridge: DexKitBridge) {
bridge.findClass {
matcher {
usingStrings("getUid", "", "_event")
}
}.findMethod {
matcher {
modifiers = Modifier.PUBLIC or Modifier.STATIC
returnType = "long"
addInvoke {
name = "parseLong"
}
addInvoke {
name = "toString"
}
}
}.single().let {
println(it)
}
}
```

This search takes `77ms`, showing a performance improvement by several tens of times.

When using `findMethod` or `findField`, the `declaredClass` condition should be avoided as much as
possible.
68 changes: 68 additions & 0 deletions doc-source/src/zh-cn/guide/performance-optimization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# 性能优化

在 DexKit 中,多种查询或许能实现同样的功能,但是性能差距却可能相差几十倍。本节将介绍一些性能优化的技巧。

在 native 层,DexKit 会维护 Dex 中的类、方法以及字段的列表,那么在几个 API 中,DexKit
是如何扫描这些列表的呢?`findClass``findMethod``findField`
的遍历顺序均是按照各自列表的先后顺序进行遍历,然后再逐一对各个条件进行匹配。

## declaredClass 条件过重

可能有些用户在使用 `findMethod``findField` 时,会使用 `declaredClass` 条件写出如下的查询:

```kotlin
private fun badCode(bridge: DexKitBridge) {
bridge.findMethod {
matcher {
declaredClass {
usingStrings("getUid", "", "_event")
}
modifiers = Modifier.PUBLIC or Modifier.STATIC
returnType = "long"
addInvoke {
name = "parseLong"
}
addInvoke {
name = "toString"
}
}
}.single().let {
println(it)
}
}
```

这个搜索耗时 `4310ms`
乍一看这个查询似乎没有什么问题,但是实际上这个查询的性能是非常差。为什么?前面提到过,`findMethod` API
会遍历一遍所有的方法,然后再逐一对各个条件进行匹配。而 method 与 class 之间却是一个多对一的关系,即一个
class 中可能包含多个 method,但是一个 method 只能属于一个 class。因此,遍历所有方法的过程中,每个 method
都会被匹配一次 `declaredClass` 条件,这就导致了性能的浪费。

那么,我们换一个思路,先搜索 declaredClass,配合链式调用就能在符合条件的类中再搜索 method,这样不就可以避免了吗?

```kotlin
private fun goodCode(bridge: DexKitBridge) {
bridge.findClass {
matcher {
usingStrings("getUid", "", "_event")
}
}.findMethod {
matcher {
modifiers = Modifier.PUBLIC or Modifier.STATIC
returnType = "long"
addInvoke {
name = "parseLong"
}
addInvoke {
name = "toString"
}
}
}.single().let {
println(it)
}
}
```

这个搜索耗时 `77ms`, 性能提升了数十倍之多。

在使用 `findMethod``findField` 时,尽量避免使用 `declaredClass` 附带过于复杂的逻辑。

0 comments on commit 271a2fa

Please sign in to comment.