mirror of
https://github.com/openharmony/developtools_bytrace.git
synced 2026-06-30 22:17:54 -04:00
update OpenHarmony 2.0 Canary
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# developtools_bytrace_standard
|
||||
|
||||
#### Description
|
||||
A tool to trace processes and monitor performance | 提供性能追踪的接口和查看性能轨迹的命令行工具
|
||||
|
||||
#### Software Architecture
|
||||
Software architecture description
|
||||
|
||||
#### Installation
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Instructions
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### Contribution
|
||||
|
||||
1. Fork the repository
|
||||
2. Create Feat_xxx branch
|
||||
3. Commit your code
|
||||
4. Create Pull Request
|
||||
|
||||
|
||||
#### Gitee Feature
|
||||
|
||||
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
|
||||
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
|
||||
4. The most valuable open source project [GVP](https://gitee.com/gvp)
|
||||
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
|
||||
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
@@ -1,37 +0,0 @@
|
||||
# developtools_bytrace_standard
|
||||
|
||||
#### 介绍
|
||||
A tool to trace processes and monitor performance | 提供性能追踪的接口和查看性能轨迹的命令行工具
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
|
||||
|
||||
#### 安装教程
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### 使用说明
|
||||
|
||||
1. xxxx
|
||||
2. xxxx
|
||||
3. xxxx
|
||||
|
||||
#### 参与贡献
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 新建 Feat_xxx 分支
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
|
||||
|
||||
#### 特技
|
||||
|
||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
||||
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
|
||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
|
||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||
Executable
+148
@@ -0,0 +1,148 @@
|
||||
# bytrace组件<a name="ZH-CN_TOPIC_0000001102209942"></a>
|
||||
|
||||
- [简介](#section152771918494)
|
||||
- [架构图](#section6808195518497)
|
||||
- [目录](#section1610792125019)
|
||||
- [说明](#section18684185975017)
|
||||
- [相关仓](#section1849151125618)
|
||||
|
||||
## 简介<a name="section152771918494"></a>
|
||||
|
||||
bytrace是开发人员用于追踪进程轨迹、查看性能的一种工具,主要对内核ftrace进行了封装和扩展,来支持用户态的打点。该工具主要分为两部分,API和命令行:
|
||||
|
||||
1. bytrace向应用开发人员暴露了打点的API,开发应用过程中可以在关键代码处调用对应API进行打点;
|
||||
2. 命令行部分通过使能对应的label,来获取打点信息。通过该工具可以打开想要查看的用户态和内核label(通过命令行“bytrace -l”,查看支持的所有label),然后通过命令行进行抓取trace信息到指定文件中,下文有具体使用指导。
|
||||
|
||||
## 架构图<a name="section6808195518497"></a>
|
||||
|
||||
.png)
|
||||
|
||||
## 目录<a name="section1610792125019"></a>
|
||||
|
||||
```
|
||||
/developtools/bytrace_standard
|
||||
├── bin # bytrace组件代码目录
|
||||
│ └── include # 头文件目录
|
||||
│ └── src # 源文件目录
|
||||
│ └── test # 测试用例目录
|
||||
├── interfaces # 对外接口存放目录
|
||||
│ └── innerkits # 对内部子系统暴露的头文件存放目录
|
||||
│ └── kits # 对外部暴露的头文件存放目录
|
||||
├── script # 脚本目录
|
||||
```
|
||||
|
||||
## 说明<a name="section18684185975017"></a>
|
||||
|
||||
使用说明
|
||||
|
||||
bytrace当前支持如下命令:
|
||||
|
||||
**表 1** 命令行列表
|
||||
|
||||
<a name="table16802195914247"></a>
|
||||
<table><thead align="left"><tr id="row14804759142412"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="p1280465972411"><a name="p1280465972411"></a><a name="p1280465972411"></a>Option</p>
|
||||
</th>
|
||||
<th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="p380414595249"><a name="p380414595249"></a><a name="p380414595249"></a>Description</p>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody><tr id="row1714512123414"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1915412133419"><a name="p1915412133419"></a><a name="p1915412133419"></a>-h,--help</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p6156126341"><a name="p6156126341"></a><a name="p6156126341"></a>查看option帮助</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row13804135982416"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p18051959152410"><a name="p18051959152410"></a><a name="p18051959152410"></a>-b <em id="i35979186184"><a name="i35979186184"></a><a name="i35979186184"></a>n</em>,--buffer_size <em id="i144491624181811"><a name="i144491624181811"></a><a name="i144491624181811"></a>n</em></p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p0805165932419"><a name="p0805165932419"></a><a name="p0805165932419"></a>指定<em id="i134241333181817"><a name="i134241333181817"></a><a name="i134241333181817"></a>n</em>(KB)内存大小用于存取trace日志,默认2048KB</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row580519592245"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p880510591241"><a name="p880510591241"></a><a name="p880510591241"></a>-t <em id="i8668143912203"><a name="i8668143912203"></a><a name="i8668143912203"></a>n</em>,--time <em id="i841433614202"><a name="i841433614202"></a><a name="i841433614202"></a>n</em></p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1480517591245"><a name="p1480517591245"></a><a name="p1480517591245"></a>用来指定trace运行的时间(单位:s),取决于需要分析过程的时间</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row4806175913247"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p980655912242"><a name="p980655912242"></a><a name="p980655912242"></a>--trace_clock <em id="i19464452217"><a name="i19464452217"></a><a name="i19464452217"></a>clock</em></p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p11806959142416"><a name="p11806959142416"></a><a name="p11806959142416"></a>trace输出的时钟类型,一般设备支持boot、global、mono、uptime、perf等,默认为boot</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1280635917242"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p180715591244"><a name="p180715591244"></a><a name="p180715591244"></a>--trace_begin</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p480795916243"><a name="p480795916243"></a><a name="p480795916243"></a>启动抓trace</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1580717599245"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p38073598242"><a name="p38073598242"></a><a name="p38073598242"></a>--trace_dump</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p148077595245"><a name="p148077595245"></a><a name="p148077595245"></a>将数据输出到指定位置(默认控制台)</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row180811592242"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p11808165922419"><a name="p11808165922419"></a><a name="p11808165922419"></a>--trace_finish</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p18809559182420"><a name="p18809559182420"></a><a name="p18809559182420"></a>停止抓trace,并将数据输出到指定位置(默认控制台)</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row2809185972420"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p2080925922418"><a name="p2080925922418"></a><a name="p2080925922418"></a>-l,--list_categories</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p38091159142414"><a name="p38091159142414"></a><a name="p38091159142414"></a>输出手机能支持的trace模块</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1880912598248"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p1681014595244"><a name="p1681014595244"></a><a name="p1681014595244"></a>--overwrite</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p12810165914248"><a name="p12810165914248"></a><a name="p12810165914248"></a>当缓冲区满的时候,将丢弃最新的信息。(默认丢弃最老的日志)</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row1181015992414"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p168101859152415"><a name="p168101859152415"></a><a name="p168101859152415"></a>-o <em id="i1367232742113"><a name="i1367232742113"></a><a name="i1367232742113"></a>filename</em>,--output <em id="i4305133012219"><a name="i4305133012219"></a><a name="i4305133012219"></a>filename</em></p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p9810559132410"><a name="p9810559132410"></a><a name="p9810559132410"></a>指定输出的目标文件名称</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="row8810155982415"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="p381145912410"><a name="p381145912410"></a><a name="p381145912410"></a>-z</p>
|
||||
</td>
|
||||
<td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="p1281117592249"><a name="p1281117592249"></a><a name="p1281117592249"></a>抓取trace后进行压缩</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
以下是常用bytrace命令示例,供开发者参考:
|
||||
|
||||
- 查询支持的label。
|
||||
|
||||
```
|
||||
bytrace -l
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```
|
||||
bytrace --list_categories
|
||||
```
|
||||
|
||||
|
||||
- 设置4M缓存,抓取10秒,抓取label为ability的trace信息。
|
||||
|
||||
```
|
||||
bytrace -b 4096 -t 10 --overwrite ability > /data/mytrace.ftrace
|
||||
```
|
||||
|
||||
|
||||
- 设置trace的输出时钟为mono。
|
||||
|
||||
```
|
||||
bytrace --trace_clock mono -b 4096 -t 10 --overwrite ability > /data/mytrace.ftrace
|
||||
```
|
||||
|
||||
|
||||
- 抓取trace后进行压缩。
|
||||
|
||||
```
|
||||
bytrace -z -b 4096 -t 10 --overwrite ability > /data/mytrace.ftrace
|
||||
```
|
||||
|
||||
|
||||
## 相关仓<a name="section1849151125618"></a>
|
||||
|
||||
研发工具链子系统
|
||||
|
||||
**developtools\_bytrace\_standard**
|
||||
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
# Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//build/ohos.gni")
|
||||
import("//developtools/bytrace_standard/bytrace.gni")
|
||||
|
||||
config("bytrace_inner_config") {
|
||||
visibility = [ ":*" ]
|
||||
include_dirs = [ "${innerkits_path}/native/include" ]
|
||||
}
|
||||
|
||||
ohos_static_library("bytrace_inner") {
|
||||
sources = [ "./src/bytrace_impl.cpp" ]
|
||||
public_configs = [ ":bytrace_inner_config" ]
|
||||
external_deps = [
|
||||
"hiviewdfx_hilog_native:libhilog",
|
||||
"ipc:ipc_core",
|
||||
"startup_l2:syspara",
|
||||
|
||||
#"distributedschedule:samgr_L2"
|
||||
]
|
||||
}
|
||||
|
||||
config("bytrace_capture_inner_config") {
|
||||
visibility = [ ":*" ]
|
||||
include_dirs = [
|
||||
"./include",
|
||||
"${innerkits_path}/native/include",
|
||||
]
|
||||
}
|
||||
|
||||
ohos_static_library("bytrace_capture_inner") {
|
||||
sources = [ "./src/bytrace_capture.cpp" ]
|
||||
public_configs = [ ":bytrace_capture_inner_config" ]
|
||||
external_deps = [
|
||||
"ipc:ipc_core",
|
||||
"startup_l2:syspara",
|
||||
]
|
||||
}
|
||||
|
||||
ohos_executable("bytrace") {
|
||||
install_enable = true
|
||||
sources = [ "./src/bytrace.cpp" ]
|
||||
|
||||
deps = [
|
||||
":bytrace_capture_inner",
|
||||
"${innerkits_path}/native:bytrace_core",
|
||||
"//third_party/zlib:libz",
|
||||
"//utils/native/base:utils",
|
||||
]
|
||||
include_dirs = [
|
||||
"${bytrace_path}/bin/include",
|
||||
"${innerkits_path}/include",
|
||||
"//utils/native/base/include",
|
||||
"//third_party/zlib",
|
||||
]
|
||||
subsystem_name = "developtools"
|
||||
part_name = "bytrace_standard"
|
||||
}
|
||||
|
||||
group("bytrace_target") {
|
||||
deps = [ ":bytrace" ]
|
||||
}
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef DEVELOPTOOLS_BYTRACE_ADAPTER_INCLUDE_BYTRACE_CAPTURE_H
|
||||
#define DEVELOPTOOLS_BYTRACE_ADAPTER_INCLUDE_BYTRACE_CAPTURE_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
const int MAX_SYS_FILES = 11;
|
||||
enum TraceType { USER, KERNEL };
|
||||
struct TagCategory {
|
||||
std::string name;
|
||||
std::string description;
|
||||
uint64_t tag;
|
||||
TraceType type;
|
||||
struct {
|
||||
std::string path;
|
||||
} sysfiles[MAX_SYS_FILES];
|
||||
};
|
||||
|
||||
std::string GetPropertyInner(const std::string& property, const std::string& value);
|
||||
bool SetPropertyInner(const std::string& property, const std::string& value);
|
||||
void RefreshBinderServices();
|
||||
bool RefreshHalServices();
|
||||
#endif // DEVELOPTOOLS_BYTRACE_ADAPTER_INCLUDE_BYTRACE_CAPTURE_H
|
||||
Executable
+867
@@ -0,0 +1,867 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bytrace.h"
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
#include "bytrace_capture.h"
|
||||
#include "securec.h"
|
||||
|
||||
using namespace std;
|
||||
namespace {
|
||||
struct option g_longOptions[] = {
|
||||
{ "buffer_size", required_argument, nullptr, 0 },
|
||||
{ "trace_clock", required_argument, nullptr, 0 },
|
||||
{ "help", no_argument, nullptr, 0 },
|
||||
{ "output", required_argument, nullptr, 0 },
|
||||
{ "time", required_argument, nullptr, 0 },
|
||||
{ "trace_begin", no_argument, nullptr, 0 },
|
||||
{ "trace_finish", no_argument, nullptr, 0 },
|
||||
{ "trace_dump", no_argument, nullptr, 0 },
|
||||
{ "list_categories", no_argument, nullptr, 0 },
|
||||
{ "overwrite", no_argument, nullptr, 0 },
|
||||
};
|
||||
const int CHUNK_SIZE = 65536;
|
||||
const int BLOCK_SIZE = 4096;
|
||||
|
||||
const string TRACE_TAG_PROPERTY = "debug.bytrace.tags.enableflags";
|
||||
|
||||
// various operating paths of ftrace
|
||||
const string TRACING_ON_PATH = "tracing_on";
|
||||
const string TRACE_PATH = "trace";
|
||||
const string TRACE_MARKER_PATH = "trace_marker";
|
||||
const string BUFFER_SIZE_PATH = "buffer_size_kb";
|
||||
const string CURRENT_TRACER_PATH = "current_tracer";
|
||||
const string TRACE_CLOCK_PATH = "trace_clock";
|
||||
const string OVER_WRITE_PATH = "options/overwrite";
|
||||
const string RECORD_TGID_PATH = "options/record-tgid";
|
||||
|
||||
// support customization of some parameters
|
||||
|
||||
const int MIN_BUFFER_SIZE = 256;
|
||||
const int MAX_BUFFER_SIZE = 307200; // 300 MB
|
||||
constexpr unsigned int MAX_OUTPUT_LEN = 255;
|
||||
const int PAGE_SIZE_KB = 4; // 4 KB
|
||||
int g_traceDuration = 5;
|
||||
int g_bufferSizeKB = 2048;
|
||||
string g_clock = "boot";
|
||||
bool g_overwrite = true;
|
||||
string g_outputFile;
|
||||
bool g_compress = false;
|
||||
|
||||
string g_traceRootPath;
|
||||
|
||||
bool g_traceStart = true;
|
||||
bool g_traceStop = true;
|
||||
bool g_traceDump = true;
|
||||
|
||||
map<string, TagCategory> g_tagMap;
|
||||
vector<uint64_t> g_userEnabledTags;
|
||||
vector<string> g_kernelEnabledPaths;
|
||||
}
|
||||
|
||||
static bool IsTraceMounted()
|
||||
{
|
||||
const string debugfsPath = "/sys/kernel/debug/tracing/";
|
||||
const string tracefsPath = "/sys/kernel/tracing/";
|
||||
|
||||
if (access((debugfsPath + TRACE_MARKER_PATH).c_str(), F_OK) != -1) {
|
||||
g_traceRootPath = debugfsPath;
|
||||
return true;
|
||||
}
|
||||
if (access((tracefsPath + TRACE_MARKER_PATH).c_str(), F_OK) != -1) {
|
||||
g_traceRootPath = tracefsPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Error: Did not find trace folder\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsFileExit(const string& filename)
|
||||
{
|
||||
return access((g_traceRootPath + filename).c_str(), F_OK) != -1;
|
||||
}
|
||||
|
||||
static bool IsWritableFile(const string& filename)
|
||||
{
|
||||
return access((g_traceRootPath + filename).c_str(), W_OK) != -1;
|
||||
}
|
||||
|
||||
static bool WriteStrToFile(const string& filename, const std::string& str)
|
||||
{
|
||||
ofstream out;
|
||||
out.open(g_traceRootPath + filename, ios::out);
|
||||
if (out.fail()) {
|
||||
fprintf(stderr, "Error: Did not open %s.\n", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
out << str;
|
||||
if (out.bad()) {
|
||||
fprintf(stderr, "Error: Did not write %s.\n", filename.c_str());
|
||||
out.close();
|
||||
return false;
|
||||
}
|
||||
out.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SetFtraceEnabled(const string& path, bool enabled)
|
||||
{
|
||||
return WriteStrToFile(path, enabled ? "1" : "0");
|
||||
}
|
||||
|
||||
static bool IsTagSupported(const string& name)
|
||||
{
|
||||
auto it = g_tagMap.find(name);
|
||||
if (it == g_tagMap.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TagCategory tagCategory = it->second;
|
||||
if (tagCategory.type != KERNEL) {
|
||||
g_userEnabledTags.push_back(tagCategory.tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SYS_FILES; i++) {
|
||||
const string path = tagCategory.sysfiles[i].path;
|
||||
if (path.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (IsWritableFile(path)) {
|
||||
g_kernelEnabledPaths.push_back(path);
|
||||
} else if (IsFileExit(path)) {
|
||||
fprintf(stderr, "Warning: category \"%s\" requires root "
|
||||
"privileges.\n", name.c_str());
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static string ReadFile(const string& filename)
|
||||
{
|
||||
ifstream fin((g_traceRootPath + filename).c_str());
|
||||
if (!fin.is_open()) {
|
||||
fprintf(stderr, "open file: %s failed!", (g_traceRootPath + filename).c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
string str((istreambuf_iterator<char>(fin)), istreambuf_iterator<char>());
|
||||
fin.close();
|
||||
return str;
|
||||
}
|
||||
|
||||
static bool SetBufferSize(int bufferSize)
|
||||
{
|
||||
if (!WriteStrToFile(CURRENT_TRACER_PATH, "nop")) {
|
||||
fprintf(stderr, "Error: write \"nop\" to %s.\n", CURRENT_TRACER_PATH.c_str());
|
||||
}
|
||||
return WriteStrToFile(BUFFER_SIZE_PATH, to_string(bufferSize));
|
||||
}
|
||||
|
||||
static bool SetClock(const string& timeclock)
|
||||
{
|
||||
string allClocks = ReadFile(TRACE_CLOCK_PATH);
|
||||
size_t begin = allClocks.find("[");
|
||||
size_t end = allClocks.find("]");
|
||||
string newClock;
|
||||
if (begin != string::npos && end != string::npos &&
|
||||
timeclock.compare(0, timeclock.size(), allClocks, begin + 1, end - begin - 1) >= 0) {
|
||||
return true;
|
||||
} else if (allClocks.find(timeclock) != string::npos) {
|
||||
newClock = timeclock;
|
||||
} else if (allClocks.find("boot") != string::npos) {
|
||||
// boot: This is the boot clock (CLOCK_BOOTTIME) and is based on the fast monotonic clock,
|
||||
// but also accounts for time in suspend.
|
||||
newClock = "boot";
|
||||
} else if (allClocks.find("mono") != string::npos) {
|
||||
// mono: uses the fast monotonic clock (CLOCK_MONOTONIC)
|
||||
// which is monotonic and is subject to NTP rate adjustments.
|
||||
newClock = "mono";
|
||||
} else if (allClocks.find("global") != string::npos) {
|
||||
// global: is in sync with all CPUs but may be a bit slower than the local clock.
|
||||
newClock = "global";
|
||||
} else {
|
||||
printf("You can set trace clock in %s\n", allClocks.c_str());
|
||||
return false;
|
||||
}
|
||||
if (newClock.size() != 0) {
|
||||
return WriteStrToFile(TRACE_CLOCK_PATH, newClock);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool SetOverWriteEnable(bool enabled)
|
||||
{
|
||||
return SetFtraceEnabled(OVER_WRITE_PATH, enabled);
|
||||
}
|
||||
|
||||
static bool SetTgidEnable(bool enabled)
|
||||
{
|
||||
return SetFtraceEnabled(RECORD_TGID_PATH, enabled);
|
||||
}
|
||||
|
||||
static bool DisableAllFtraceEvents()
|
||||
{
|
||||
bool isTrue = true;
|
||||
for (auto it = g_tagMap.begin(); it != g_tagMap.end(); ++it) {
|
||||
TagCategory tag = it->second;
|
||||
if (tag.type != KERNEL) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < MAX_SYS_FILES; i++) {
|
||||
const string path = tag.sysfiles[i].path;
|
||||
if (path.size() > 0 && IsWritableFile(path)) {
|
||||
isTrue = isTrue && SetFtraceEnabled(path, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return isTrue;
|
||||
}
|
||||
|
||||
static bool SetProperty(const string& property, const string& value)
|
||||
{
|
||||
return SetPropertyInner(property, value);
|
||||
}
|
||||
|
||||
static bool SetTraceTagsEnabled(uint64_t tags)
|
||||
{
|
||||
string value = to_string(tags);
|
||||
return SetProperty(TRACE_TAG_PROPERTY, value);
|
||||
}
|
||||
|
||||
static bool RefreshServices()
|
||||
{
|
||||
RefreshBinderServices();
|
||||
return RefreshHalServices();
|
||||
}
|
||||
|
||||
static bool SetUserSpaceSettings()
|
||||
{
|
||||
uint64_t enabledTags = 0;
|
||||
for (auto tag: g_userEnabledTags) {
|
||||
enabledTags |= tag;
|
||||
}
|
||||
return SetTraceTagsEnabled(enabledTags) && RefreshServices();
|
||||
}
|
||||
|
||||
static bool ClearUserSpaceSettings()
|
||||
{
|
||||
return SetTraceTagsEnabled(0) && RefreshServices();
|
||||
}
|
||||
|
||||
static bool SetKernelSpaceSettings()
|
||||
{
|
||||
bool isTrue = SetBufferSize(g_bufferSizeKB) && SetClock(g_clock) &&
|
||||
SetOverWriteEnable(g_overwrite) && DisableAllFtraceEvents();
|
||||
for (const auto& path : g_kernelEnabledPaths) {
|
||||
SetFtraceEnabled(path, true);
|
||||
}
|
||||
return isTrue;
|
||||
}
|
||||
|
||||
static bool ClearKernelSpaceSettings()
|
||||
{
|
||||
return DisableAllFtraceEvents() && SetOverWriteEnable(true) && SetBufferSize(1) && SetClock("boot");
|
||||
}
|
||||
|
||||
static bool SetViewStyle()
|
||||
{
|
||||
return SetTgidEnable(true);
|
||||
}
|
||||
|
||||
static void ShowListCategory()
|
||||
{
|
||||
printf(" %18s description:\n", "tagName:");
|
||||
for (auto it = g_tagMap.begin(); it != g_tagMap.end(); ++it) {
|
||||
string key = it->first;
|
||||
TagCategory tag = it->second;
|
||||
if (IsTagSupported(key)) {
|
||||
printf(" %18s - %s\n", tag.name.c_str(), tag.description.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowHelp(const string& cmd)
|
||||
{
|
||||
printf("usage: %s [options] [categories...]\n", cmd.c_str());
|
||||
printf("options include:\n"
|
||||
" -b N Sets the size of the buffer (KB) for storing and reading traces. The default \n"
|
||||
" buffer size is 2048 KB.\n"
|
||||
" --buffer_size N Like \"-b N\".\n"
|
||||
" -l Lists available bytrace categories.\n"
|
||||
" --list_categories Like \"-l\".\n"
|
||||
" -t N Sets the bytrace running duration in seconds (5s by default), which depends on"
|
||||
" the time required for analysis.\n"
|
||||
" --time N Like \"-t N\".\n"
|
||||
" --trace_clock clock\n"
|
||||
" Sets the type of the clock for adding a timestamp to a trace, which can be\n"
|
||||
" boot (default), global, mono, uptime, or perf.\n"
|
||||
" --trace_begin Starts capturing traces.\n"
|
||||
" --trace_dump Dumps traces to a specified path (stdout by default).\n"
|
||||
" --trace_finish Stops capturing traces and dumps traces to a specified path (stdout by default).\n"
|
||||
" --overwrite Sets the action to take when the buffer is full. If this option is used,\n"
|
||||
" the latest traces are discarded; if this option is not used (default setting),\n"
|
||||
" the earliest traces are discarded.\n"
|
||||
" -o filename Specifies the name of the target file (stdout by default).\n"
|
||||
" --output filename\n"
|
||||
" Like \"-o filename\".\n"
|
||||
" -z Compresses a captured trace.\n"
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool StrToNum(const std::string& sString, T &tX)
|
||||
{
|
||||
std::istringstream iStream(sString);
|
||||
return (iStream >> tX) ? true : false;
|
||||
}
|
||||
|
||||
static void ParseLongOpt(const string& cmd,
|
||||
int optionIndex,
|
||||
bool& isTrue)
|
||||
{
|
||||
if (!strcmp(g_longOptions[optionIndex].name, "buffer_size")) {
|
||||
if (!StrToNum(optarg, g_bufferSizeKB)) {
|
||||
printf("Error: the bufferSize is illegal input. eg: \"--buffer_size 1024.\"\n");
|
||||
isTrue &= false;
|
||||
} else if (g_bufferSizeKB < MIN_BUFFER_SIZE || g_bufferSizeKB > MAX_BUFFER_SIZE) {
|
||||
printf("Error: the buffer size should be within 256 KB to 300 MB. eg: \"--buffer_size 1024.\"\n");
|
||||
isTrue &= false;
|
||||
}
|
||||
g_bufferSizeKB = g_bufferSizeKB / PAGE_SIZE_KB * PAGE_SIZE_KB;
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "trace_clock")) {
|
||||
regex re("[a-zA-Z]{4,6}");
|
||||
if (regex_match(optarg, re)) {
|
||||
g_clock = optarg;
|
||||
} else {
|
||||
printf("Error: \"--trace_clock\" is illegal input. eg: \"--trace_clock boot.\"\n");
|
||||
isTrue &= false;
|
||||
}
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "help")) {
|
||||
ShowHelp(cmd);
|
||||
isTrue &= false;
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "time")) {
|
||||
if (!StrToNum(optarg, g_traceDuration)) {
|
||||
printf("Error: the time is illegal input. eg: \"--time 5.\"\n");
|
||||
isTrue &= false;
|
||||
} else if (g_traceDuration < 1) {
|
||||
printf("Error: \"-t %s\" to be greater than zero. eg: \"--time 5\"\n", optarg);
|
||||
isTrue &= false;
|
||||
}
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "list_categories")) {
|
||||
ShowListCategory();
|
||||
isTrue &= false;
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "output")) {
|
||||
struct stat buf;
|
||||
size_t len = strnlen(optarg, MAX_OUTPUT_LEN);
|
||||
if (len == MAX_OUTPUT_LEN || len < 1 ||
|
||||
(stat(optarg, &buf) == 0 && (buf.st_mode & S_IFDIR) != 0)) {
|
||||
printf("Error: output file is illegal.\n");
|
||||
isTrue &= false;
|
||||
} else {
|
||||
g_outputFile = optarg;
|
||||
}
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "overwrite")) {
|
||||
g_overwrite = false;
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "trace_begin")) {
|
||||
g_traceStart = true;
|
||||
g_traceStop = false;
|
||||
g_traceDump = false;
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "trace_finish")) {
|
||||
g_traceStart = false;
|
||||
g_traceStop = true;
|
||||
g_traceDump = true;
|
||||
} else if (!strcmp(g_longOptions[optionIndex].name, "trace_dump")) {
|
||||
g_traceStart = false;
|
||||
g_traceStop = false;
|
||||
g_traceDump = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ParseOpt(int opt, char** argv, int optIndex)
|
||||
{
|
||||
bool isTrue = true;
|
||||
switch (opt) {
|
||||
case 'b': {
|
||||
if (!StrToNum(optarg, g_bufferSizeKB)) {
|
||||
printf("Error: the bufferSize is illegal input. eg: \"--buffer_size 1024.\"\n");
|
||||
isTrue &= false;
|
||||
} else if (g_bufferSizeKB < MIN_BUFFER_SIZE || g_bufferSizeKB > MAX_BUFFER_SIZE) {
|
||||
printf("Error: the buffer size should be within 256 KB to 300 MB. eg: \"--buffer_size 1024.\"\n");
|
||||
isTrue &= false;
|
||||
}
|
||||
g_bufferSizeKB = g_bufferSizeKB / PAGE_SIZE_KB * PAGE_SIZE_KB;
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
ShowHelp(argv[0]);
|
||||
isTrue &= false;
|
||||
break;
|
||||
case 'l':
|
||||
ShowListCategory();
|
||||
isTrue &= false;
|
||||
break;
|
||||
case 't': {
|
||||
if (!StrToNum(optarg, g_traceDuration)) {
|
||||
printf("Error: the time is illegal input. eg: \"--time 5.\"\n");
|
||||
isTrue &= false;
|
||||
} else if (g_traceDuration < 1) {
|
||||
printf("Error: \"-t %s\" to be greater than zero. eg: \"--time 5\"\n", optarg);
|
||||
isTrue &= false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'o': {
|
||||
struct stat buf;
|
||||
size_t len = strnlen(optarg, MAX_OUTPUT_LEN);
|
||||
if (len == MAX_OUTPUT_LEN || len < 1 ||
|
||||
(stat(optarg, &buf) == 0 && (buf.st_mode & S_IFDIR) != 0)) {
|
||||
printf("Error: output file is illegal.\n");
|
||||
isTrue &= false;
|
||||
} else {
|
||||
g_outputFile = optarg;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'z':
|
||||
g_compress = true;
|
||||
break;
|
||||
case 0: // long options
|
||||
ParseLongOpt(argv[0], optIndex, isTrue);
|
||||
break;
|
||||
default:
|
||||
ShowHelp(argv[0]);
|
||||
isTrue &= false;
|
||||
break;
|
||||
}
|
||||
return isTrue;
|
||||
}
|
||||
|
||||
static void IsInvalidOpt(int argc, char** argv)
|
||||
{
|
||||
for (int i = optind; i < argc; i++) {
|
||||
if (!IsTagSupported(argv[i])) {
|
||||
fprintf(stderr, "Error: \"%s\" is not support category on this device.\n", argv[i]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool HandleOpt(int argc, char** argv)
|
||||
{
|
||||
bool isTrue = true;
|
||||
int opt = 0;
|
||||
int optionIndex = 0;
|
||||
string shortOption = "b:c:hlo:t:z";
|
||||
int argcSize = argc;
|
||||
while (isTrue && argcSize-- > 0) {
|
||||
opt = getopt_long(argc, argv, shortOption.c_str(), g_longOptions, &optionIndex);
|
||||
if (opt < 0) {
|
||||
IsInvalidOpt(argc, argv);
|
||||
break;
|
||||
}
|
||||
isTrue &= ParseOpt(opt, argv, optionIndex);
|
||||
}
|
||||
return isTrue;
|
||||
}
|
||||
|
||||
static bool TruncateFile(const string& path)
|
||||
{
|
||||
int fd = creat((g_traceRootPath + path).c_str(), 0);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "Error: clear %s: %s (%d)\n", (g_traceRootPath + path).c_str(),
|
||||
strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
fd = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ClearTrace()
|
||||
{
|
||||
return TruncateFile(TRACE_PATH);
|
||||
}
|
||||
|
||||
static bool StartTrace()
|
||||
{
|
||||
if (!SetFtraceEnabled(TRACING_ON_PATH, true)) {
|
||||
return false;
|
||||
}
|
||||
ClearTrace();
|
||||
printf("capturing trace...\n");
|
||||
fflush(stdout);
|
||||
struct timespec ts = {0, 0};
|
||||
ts.tv_sec = g_traceDuration;
|
||||
ts.tv_nsec = 0;
|
||||
while ((nanosleep(&ts, &ts) == -1) && (errno == EINTR)) {}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool StopTrace()
|
||||
{
|
||||
return SetFtraceEnabled(TRACING_ON_PATH, false);
|
||||
}
|
||||
|
||||
static void DumpCompressedTrace(int traceFd, int outFd)
|
||||
{
|
||||
z_stream zs { 0 };
|
||||
ssize_t bytesWritten;
|
||||
ssize_t bytesRead;
|
||||
if (memset_s(&zs, sizeof(zs), 0, sizeof(zs)) != 0) {
|
||||
fprintf(stderr, "Error: zip stream buffer init failed.");
|
||||
return;
|
||||
}
|
||||
int ret = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
|
||||
if (ret != Z_OK) {
|
||||
fprintf(stderr, "Error: initializing zlib: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
int have;
|
||||
unique_ptr<uint8_t> in = std::make_unique<uint8_t>(CHUNK_SIZE);
|
||||
unique_ptr<uint8_t> out = std::make_unique<uint8_t>(CHUNK_SIZE);
|
||||
int flush = Z_NO_FLUSH;
|
||||
if (!in || !out) {
|
||||
fprintf(stderr, "Error: couldn't allocate buffers.\n");
|
||||
return;
|
||||
}
|
||||
do {
|
||||
bytesRead = TEMP_FAILURE_RETRY(read(traceFd, in.get(), CHUNK_SIZE));
|
||||
if (bytesRead == 0) {
|
||||
flush = Z_FINISH;
|
||||
} else if (bytesRead == -1) {
|
||||
fprintf(stderr, "Error: reading trace: %s (%d)\n", strerror(errno), errno);
|
||||
break;
|
||||
}
|
||||
zs.next_in = reinterpret_cast<Bytef*>(in.get());
|
||||
zs.avail_in = bytesRead;
|
||||
do {
|
||||
zs.next_out = reinterpret_cast<Bytef*>(out.get());
|
||||
zs.avail_out = CHUNK_SIZE;
|
||||
ret = deflate(&zs, flush);
|
||||
if (ret != Z_OK) {
|
||||
fprintf(stderr, "Error: deflate zlib: %d\n", ret);
|
||||
break;
|
||||
}
|
||||
have = CHUNK_SIZE - zs.avail_out;
|
||||
bytesWritten = TEMP_FAILURE_RETRY(write(outFd, out.get(), have));
|
||||
if (bytesWritten < 0 || (static_cast<size_t>(bytesWritten) < static_cast<size_t>(have)) ||
|
||||
bytesWritten == -1) {
|
||||
fprintf(stderr, "Error: writing deflated trace: %s (%d)\n", strerror(errno), errno);
|
||||
break;
|
||||
}
|
||||
} while (zs.avail_out == 0);
|
||||
} while (flush != Z_FINISH);
|
||||
deflateEnd(&zs);
|
||||
}
|
||||
|
||||
static void DumpTrace(int outFd, const string& path)
|
||||
{
|
||||
int traceFd = open((g_traceRootPath + path).c_str(), O_RDWR);
|
||||
if (traceFd == -1) {
|
||||
fprintf(stderr, "error opening %s: %s (%d)\n", path.c_str(),
|
||||
strerror(errno), errno);
|
||||
return;
|
||||
}
|
||||
ssize_t bytesWritten;
|
||||
ssize_t bytesRead;
|
||||
if (g_compress) {
|
||||
DumpCompressedTrace(traceFd, outFd);
|
||||
} else {
|
||||
char buffer[BLOCK_SIZE];
|
||||
do {
|
||||
bytesRead = TEMP_FAILURE_RETRY(read(traceFd, buffer, BLOCK_SIZE));
|
||||
if ((bytesRead == 0) || (bytesRead == -1)) {
|
||||
break;
|
||||
}
|
||||
bytesWritten = TEMP_FAILURE_RETRY(write(outFd, buffer, bytesRead));
|
||||
} while (bytesWritten > 0);
|
||||
}
|
||||
close(traceFd);
|
||||
}
|
||||
|
||||
static bool MarkOthersClockSync()
|
||||
{
|
||||
constexpr unsigned int bufferSize = 128; // buffer size
|
||||
char buffer[bufferSize] = { 0 };
|
||||
int fd = open((g_traceRootPath + TRACE_MARKER_PATH).c_str(), O_WRONLY);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "Error: opening %s: %s (%d)\n", TRACE_MARKER_PATH.c_str(), strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct timespec mts = {0, 0};
|
||||
struct timespec rts = {0, 0};
|
||||
if (clock_gettime(CLOCK_REALTIME, &rts) == -1) {
|
||||
fprintf(stderr, "Error: get realtime %s (%d)\n", strerror(errno), errno);
|
||||
close(fd);
|
||||
return false;
|
||||
} else if (clock_gettime(CLOCK_MONOTONIC, &mts) == -1) {
|
||||
fprintf(stderr, "Error: get parent_ts %s (%d)\n", strerror(errno), errno);
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
constexpr unsigned int nanoSeconds = 1000000000; // seconds converted to nanoseconds
|
||||
constexpr unsigned int nanoToMill = 1000000; // millisecond converted to nanoseconds
|
||||
constexpr float nanoToSecond = 1000000000.0f; // consistent with the ftrace timestamp format
|
||||
int len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1,
|
||||
"trace_event_clock_sync: realtime_ts=%" PRId64 "\n",
|
||||
static_cast<int64_t>((rts.tv_sec * nanoSeconds + rts.tv_nsec) / nanoToMill));
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "Error: entering data into buffer %s (%d)\n", strerror(errno), errno);
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
if (write(fd, buffer, len) < 0) {
|
||||
fprintf(stderr, "Error: writing clock sync marker %s (%d)\n", strerror(errno), errno);
|
||||
}
|
||||
len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "trace_event_clock_sync: parent_ts=%f\n",
|
||||
static_cast<float>(((static_cast<float>(mts.tv_sec)) * nanoSeconds + mts.tv_nsec) / nanoToSecond));
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "Error: entering data into buffer %s (%d)\n", strerror(errno), errno);
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
if (write(fd, buffer, len) < 0) {
|
||||
fprintf(stderr, "Error: writing clock sync marker %s (%d)\n", strerror(errno), errno);
|
||||
}
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void InitDiskSupportTags()
|
||||
{
|
||||
g_tagMap["disk"] = { "disk", "Disk I/O", 0, KERNEL, {
|
||||
{ "events/f2fs/f2fs_sync_file_enter/enable" },
|
||||
{ "events/f2fs/f2fs_sync_file_exit/enable" },
|
||||
{ "events/f2fs/f2fs_write_begin/enable" },
|
||||
{ "events/f2fs/f2fs_write_end/enable" },
|
||||
{ "events/ext4/ext4_da_write_begin/enable" },
|
||||
{ "events/ext4/ext4_da_write_end/enable" },
|
||||
{ "events/ext4/ext4_sync_file_enter/enable" },
|
||||
{ "events/ext4/ext4_sync_file_exit/enable" },
|
||||
{ "events/block/block_rq_issue/enable" },
|
||||
{ "events/block/block_rq_complete/enable" },
|
||||
}};
|
||||
g_tagMap["mmc"] = { "mmc", "eMMC commands", 0, KERNEL, {
|
||||
{ "events/mmc/enable" },
|
||||
}};
|
||||
}
|
||||
|
||||
static void InitHardwareSupportTags()
|
||||
{
|
||||
g_tagMap["irq"] = { "irq", "IRQ Events", 0, KERNEL, {
|
||||
{ "events/irq/enable" },
|
||||
{ "events/ipi/enable" },
|
||||
}};
|
||||
g_tagMap["irqoff"] = { "irqoff", "IRQ-disabled code section tracing", 0, KERNEL, {
|
||||
{ "events/preemptirq/irq_enable/enable" },
|
||||
{ "events/preemptirq/irq_disable/enable" },
|
||||
}};
|
||||
InitDiskSupportTags();
|
||||
g_tagMap["i2c"] = { "i2c", "I2C Events", 0, KERNEL, {
|
||||
{ "events/i2c/enable" },
|
||||
{ "events/i2c/i2c_read/enable" },
|
||||
{ "events/i2c/i2c_write/enable" },
|
||||
{ "events/i2c/i2c_result/enable" },
|
||||
{ "events/i2c/i2c_reply/enable" },
|
||||
{ "events/i2c/smbus_read/enable" },
|
||||
{ "events/i2c/smbus_write/enable" },
|
||||
{ "events/i2c/smbus_result/enable" },
|
||||
{ "events/i2c/smbus_reply/enable" },
|
||||
}};
|
||||
g_tagMap["freq"] = { "freq", "CPU Frequency", 0, KERNEL, {
|
||||
{ "events/power/cpu_frequency/enable" },
|
||||
{ "events/power/clock_set_rate/enable" },
|
||||
{ "events/power/clock_disable/enable" },
|
||||
{ "events/power/clock_enable/enable" },
|
||||
{ "events/clk/clk_set_rate/enable" },
|
||||
{ "events/clk/clk_disable/enable" },
|
||||
{ "events/clk/clk_enable/enable" },
|
||||
{ "events/power/cpu_frequency_limits/enable" },
|
||||
}};
|
||||
g_tagMap["ufs"] = { "ufs", "UFS commands", 0, KERNEL, {
|
||||
{ "events/ufs/enable" },
|
||||
}};
|
||||
g_tagMap["regulators"] = { "regulators", "Voltage and Current Regulators", 0, KERNEL, {
|
||||
{ "events/regulator/enable" },
|
||||
}};
|
||||
g_tagMap["membus"] = { "membus", "Memory Bus Utilization", 0, KERNEL, {
|
||||
{ "events/memory_bus/enable" },
|
||||
}};
|
||||
}
|
||||
|
||||
static void InitKernelSupportTags()
|
||||
{
|
||||
g_tagMap["sched"] = { "sched", "CPU Scheduling", 0, KERNEL, {
|
||||
{ "events/sched/sched_switch/enable" },
|
||||
{ "events/sched/sched_wakeup/enable" },
|
||||
{ "events/sched/sched_wakeup_new/enable" },
|
||||
{ "events/sched/sched_waking/enable" },
|
||||
{ "events/sched/sched_blocked_reason/enable" },
|
||||
{ "events/sched/sched_pi_setprio/enable" },
|
||||
{ "events/sched/sched_process_exit/enable" },
|
||||
{ "events/cgroup/enable" },
|
||||
{ "events/oom/oom_score_adj_update/enable" },
|
||||
{ "events/task/task_rename/enable" },
|
||||
{ "events/task/task_newtask/enable" },
|
||||
}};
|
||||
g_tagMap["preemptoff"] = { "preemptoff", "Preempt-disabled code section tracing", 0, KERNEL, {
|
||||
{ "events/preemptirq/preempt_enable/enable" },
|
||||
{ "events/preemptirq/preempt_disable/enable" },
|
||||
}};
|
||||
g_tagMap["idle"] = { "idle", "CPU Idle", 0, KERNEL, {
|
||||
{ "events/power/cpu_idle/enable" },
|
||||
}};
|
||||
|
||||
g_tagMap["load"] = { "load", "CPU Load", 0, KERNEL, {
|
||||
{ "events/cpufreq_interactive/enable" },
|
||||
}};
|
||||
g_tagMap["sync"] = { "sync", "Synchronization", 0, KERNEL, {
|
||||
// linux kernel > 4.9
|
||||
{ "events/dma_fence/enable" },
|
||||
}};
|
||||
g_tagMap["workq"] = { "workq", "Kernel Workqueues", 0, KERNEL, {
|
||||
{ "events/workqueue/enable" },
|
||||
}};
|
||||
g_tagMap["memreclaim"] = { "memreclaim", "Kernel Memory Reclaim", 0, KERNEL, {
|
||||
{ "events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
|
||||
{ "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
|
||||
{ "events/vmscan/mm_vmscan_kswapd_wake/enable" },
|
||||
{ "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
|
||||
{ "events/lowmemorykiller/enable" },
|
||||
}};
|
||||
g_tagMap["pagecache"] = { "pagecache", "Page cache", 0, KERNEL, {
|
||||
{ "events/filemap/enable" },
|
||||
}};
|
||||
g_tagMap["memory"] = { "memory", "Memory", 0, KERNEL, {
|
||||
{ "events/kmem/rss_stat/enable" },
|
||||
{ "events/kmem/ion_heap_grow/enable" },
|
||||
{ "events/kmem/ion_heap_shrink/enable" },
|
||||
}};
|
||||
InitHardwareSupportTags();
|
||||
}
|
||||
|
||||
static void InitAllSupportTags()
|
||||
{
|
||||
// OHOS
|
||||
g_tagMap["ohos"] = { "ohos", "OpenHarmony", BYTRACE_TAG_OHOS, USER, {}};
|
||||
g_tagMap["ability"] = { "ability", "Ability Manager", BYTRACE_TAG_ABILITY_MANAGER, USER, {}};
|
||||
g_tagMap["zcamera"] = { "zcamera", "OpenHarmony Camera Module", BYTRACE_TAG_ZCAMERA, USER, {}};
|
||||
g_tagMap["zmedia"] = { "zmedia", "OpenHarmony Media Module", BYTRACE_TAG_ZMEDIA, USER, {}};
|
||||
g_tagMap["zimage"] = { "zimage", "OpenHarmony Image Module", BYTRACE_TAG_ZIMAGE, USER, {}};
|
||||
g_tagMap["zaudio"] = { "zaudio", "OpenHarmony Audio Module", BYTRACE_TAG_ZAUDIO, USER, {}};
|
||||
g_tagMap["distributeddatamgr"] = { "distributeddatamgr", "Distributed Data Manager",
|
||||
BYTRACE_TAG_DISTRIBUTEDDATA, USER, {}};
|
||||
g_tagMap["mdfs"] = { "mdfs", "Mobile Distributed File System", BYTRACE_TAG_MDFS, USER, {}};
|
||||
g_tagMap["graphic"] = { "graphic", "Graphic Module", BYTRACE_TAG_GRAPHIC_AGP, USER, {}};
|
||||
g_tagMap["ace"] = { "ace", "ACE development framework", BYTRACE_TAG_ACE, USER, {}};
|
||||
g_tagMap["notification"] = { "notification", "Notification Module", BYTRACE_TAG_NOTIFICATION, USER, {}};
|
||||
g_tagMap["app"] = { "app", "APP Module", BYTRACE_TAG_APP, USER, {}};
|
||||
g_tagMap["zbinder"] = { "zbinder", "Harmony binder communication", 0, KERNEL, {
|
||||
{ "events/zbinder/enable" },
|
||||
}};
|
||||
|
||||
// Kernel os
|
||||
InitKernelSupportTags();
|
||||
}
|
||||
|
||||
static void InterruptExit(int signo)
|
||||
{
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
signal(SIGKILL, InterruptExit);
|
||||
signal(SIGINT, InterruptExit);
|
||||
|
||||
if (!IsTraceMounted()) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
InitAllSupportTags();
|
||||
|
||||
if (!HandleOpt(argc, argv)) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (!SetKernelSpaceSettings()) {
|
||||
ClearKernelSpaceSettings();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (!SetUserSpaceSettings()) {
|
||||
ClearKernelSpaceSettings();
|
||||
ClearUserSpaceSettings();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
bool isTrue = true;
|
||||
|
||||
if (g_traceStart) {
|
||||
SetViewStyle();
|
||||
isTrue &= StartTrace();
|
||||
}
|
||||
|
||||
isTrue &= MarkOthersClockSync();
|
||||
|
||||
if (g_traceStop) {
|
||||
isTrue &= StopTrace();
|
||||
}
|
||||
|
||||
if (isTrue && g_traceDump) {
|
||||
int outFd = STDOUT_FILENO;
|
||||
if (g_outputFile.size() > 0) {
|
||||
printf("write trace to %s\n", g_outputFile.c_str());
|
||||
outFd = open(g_outputFile.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
}
|
||||
if (outFd == -1) {
|
||||
printf("Failed to open '%s', err=%d", g_outputFile.c_str(), errno);
|
||||
} else {
|
||||
dprintf(outFd, "TRACE:\n");
|
||||
DumpTrace(outFd, TRACE_PATH);
|
||||
if (outFd != STDOUT_FILENO) {
|
||||
close(outFd);
|
||||
outFd = -1;
|
||||
}
|
||||
}
|
||||
ClearTrace();
|
||||
}
|
||||
|
||||
ClearUserSpaceSettings();
|
||||
ClearKernelSpaceSettings();
|
||||
|
||||
return isTrue;
|
||||
}
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bytrace_capture.h"
|
||||
#include "bytrace.h"
|
||||
#include "parameters.h"
|
||||
|
||||
using namespace std;
|
||||
bool SetPropertyInner(const string& property, const string& value)
|
||||
{
|
||||
bool result = OHOS::system::SetParameter(property, value);
|
||||
if (!result) {
|
||||
fprintf(stderr, "Error: Failed to set %s property.\n", property.c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetPropertyInner(const std::string& property, const std::string& value)
|
||||
{
|
||||
return OHOS::system::GetParameter(property, value);
|
||||
}
|
||||
|
||||
void RefreshBinderServices()
|
||||
{
|
||||
}
|
||||
|
||||
bool RefreshHalServices()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Executable
+213
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <atomic>
|
||||
#include <climits>
|
||||
#include <fcntl.h>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include "bytrace.h"
|
||||
#include "hilog/log.h"
|
||||
#include "parameters.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace OHOS::HiviewDFX;
|
||||
|
||||
#define EXPECTANTLY(exp) (__builtin_expect(!!(exp), true))
|
||||
#define UNEXPECTANTLY(exp) (__builtin_expect(!!(exp), false))
|
||||
|
||||
namespace {
|
||||
int g_markerFd = -1;
|
||||
std::once_flag g_onceFlag;
|
||||
|
||||
std::atomic<bool> g_isBytraceInit(false);
|
||||
std::atomic<uint64_t> g_tagsProperty(BYTRACE_TAG_NOT_READY);
|
||||
|
||||
const std::string KEY_TRACE_TAG = "debug.bytrace.tags.enableflags";
|
||||
const std::string KEY_APP_NUMBER = "debug.bytrace.app_number";
|
||||
const std::string KEY_RO_DEBUGGABLE = "ro.debuggable";
|
||||
|
||||
constexpr int NAME_MAX_SIZE = 1000;
|
||||
static std::vector<std::string> g_markTypes = {"B", "E", "S", "F", "C"};
|
||||
enum MarkerType { MARKER_BEGIN, MARKER_END, MARKER_ASYNC_BEGIN, MARKER_ASYNC_END, MARKER_INT, MARKER_MAX };
|
||||
|
||||
bool IsAppValid()
|
||||
{
|
||||
// Judge if application-level tracing is enabled.
|
||||
if (OHOS::system::GetBoolParameter(KEY_RO_DEBUGGABLE, 0)) {
|
||||
std::ifstream fs;
|
||||
fs.open("/proc/self/cmdline");
|
||||
if (!fs.is_open()) {
|
||||
fprintf(stderr, "IsAppValid, open /proc/self/cmdline failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string lineStr;
|
||||
std::getline(fs, lineStr);
|
||||
std::string keyPrefix = "debug.bytrace.app_";
|
||||
int nums = OHOS::system::GetIntParameter<int>(KEY_APP_NUMBER, 0);
|
||||
for (int i = 0; i < nums; i++) {
|
||||
std::string keyStr = keyPrefix + std::to_string(i);
|
||||
std::string val = OHOS::system::GetParameter(keyStr, "");
|
||||
if (val == "*" || val == lineStr) {
|
||||
fs.close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t GetSysParamTags()
|
||||
{
|
||||
// Get the system parameters of KEY_TRACE_TAG.
|
||||
std::string tagStr = OHOS::system::GetParameter(KEY_TRACE_TAG, "");
|
||||
uint64_t tags = std::stoull(tagStr);
|
||||
if (tagStr == "" || tags == ULLONG_MAX) {
|
||||
fprintf(stderr, "GetSysParamTags error tag: %s.\n", tagStr.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
tags = IsAppValid() ? (tags | BYTRACE_TAG_APP) : (tags & (~BYTRACE_TAG_APP));
|
||||
return (tags | BYTRACE_TAG_ALWAYS) & BYTRACE_TAG_VALID_MASK;
|
||||
}
|
||||
|
||||
// open file "trace_marker".
|
||||
void OpenTraceMarkerFile()
|
||||
{
|
||||
const std::string debugFile = "/sys/kernel/debug/tracing/trace_marker";
|
||||
const std::string traceFile = "/sys/kernel/tracing/trace_marker";
|
||||
g_markerFd = open(debugFile.c_str(), O_WRONLY | O_CLOEXEC);
|
||||
if (g_markerFd == -1) {
|
||||
g_markerFd = open(traceFile.c_str(), O_WRONLY | O_CLOEXEC);
|
||||
if (g_markerFd == -1) {
|
||||
fprintf(stderr, "Error opening trace file.\n");
|
||||
g_tagsProperty = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
g_tagsProperty = GetSysParamTags();
|
||||
g_isBytraceInit = true;
|
||||
}
|
||||
}; // namespace
|
||||
|
||||
inline void AddBytraceMarker(MarkerType type, uint64_t tag, std::string name, std::string value)
|
||||
{
|
||||
if (UNEXPECTANTLY(!g_isBytraceInit)) {
|
||||
std::call_once(g_onceFlag, OpenTraceMarkerFile);
|
||||
}
|
||||
if (UNEXPECTANTLY(g_tagsProperty & tag)) {
|
||||
// record fomart: "type|pid|name value".
|
||||
std::string record = g_markTypes[type] + "|";
|
||||
record += std::to_string(getpid()) + "|";
|
||||
record += (name.size() < NAME_MAX_SIZE) ? name : name.substr(0, NAME_MAX_SIZE);
|
||||
record += " " + value;
|
||||
write(g_markerFd, record.c_str(), record.size());
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateTraceLabel()
|
||||
{
|
||||
if (!g_isBytraceInit) {
|
||||
return;
|
||||
}
|
||||
g_tagsProperty = GetSysParamTags();
|
||||
}
|
||||
|
||||
void StartTrace(uint64_t label, const string& value, float limit)
|
||||
{
|
||||
string traceName = "H:" + value;
|
||||
AddBytraceMarker(MARKER_BEGIN, label, traceName, "");
|
||||
}
|
||||
|
||||
void StartTraceDebug(uint64_t label, const string& value, float limit)
|
||||
{
|
||||
#if (TRACE_LEVEL >= DEBUG_LEVEL)
|
||||
string traceName = "H:" + value + GetHiTraceInfo();
|
||||
AddBytraceMarker(MARKER_BEGIN, label, traceName, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
void FinishTrace(uint64_t label, const string& value)
|
||||
{
|
||||
AddBytraceMarker(MARKER_END, label, "", "");
|
||||
}
|
||||
|
||||
void FinishTraceDebug(uint64_t label, const string& value)
|
||||
{
|
||||
#if (TRACE_LEVEL >= DEBUG_LEVEL)
|
||||
AddBytraceMarker(MARKER_END, label, "", "");
|
||||
#endif
|
||||
}
|
||||
|
||||
void StartAsyncTrace(uint64_t label, const string& value, int32_t taskId, float limit)
|
||||
{
|
||||
string traceName = "H:" + value;
|
||||
AddBytraceMarker(MARKER_ASYNC_BEGIN, label, traceName, std::to_string(taskId));
|
||||
}
|
||||
|
||||
void StartAsyncTraceDebug(uint64_t label, const string& value, int32_t taskId, float limit)
|
||||
{
|
||||
#if (TRACE_LEVEL >= DEBUG_LEVEL)
|
||||
string traceName = "H:" + value;
|
||||
AddBytraceMarker(MARKER_ASYNC_BEGIN, label, traceName, std::to_string(taskId));
|
||||
#endif
|
||||
}
|
||||
|
||||
void FinishAsyncTrace(uint64_t label, const string& value, int32_t taskId)
|
||||
{
|
||||
string traceName = "H:" + value;
|
||||
AddBytraceMarker(MARKER_ASYNC_END, label, traceName, std::to_string(taskId));
|
||||
}
|
||||
|
||||
void FinishAsyncTraceDebug(uint64_t label, const string& value, int32_t taskId)
|
||||
{
|
||||
#if (TRACE_LEVEL >= DEBUG_LEVEL)
|
||||
string traceName = "H:" + value;
|
||||
AddBytraceMarker(MARKER_ASYNC_END, label, traceName, std::to_string(taskId));
|
||||
#endif
|
||||
}
|
||||
|
||||
void MiddleTrace(uint64_t label, const string& beforeValue, const std::string& afterValue)
|
||||
{
|
||||
string traceName = "H:" + afterValue;
|
||||
AddBytraceMarker(MARKER_END, label, "", "");
|
||||
AddBytraceMarker(MARKER_BEGIN, label, traceName, "");
|
||||
}
|
||||
|
||||
void MiddleTraceDebug(uint64_t label, const string& beforeValue, const std::string& afterValue)
|
||||
{
|
||||
#if (TRACE_LEVEL >= DEBUG_LEVEL)
|
||||
string traceName = "H:" + afterValue + GetTraceInfo();
|
||||
AddBytraceMarker(MARKER_END, label, "", "");
|
||||
AddBytraceMarker(MARKER_BEGIN, label, traceName, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
void CountTrace(uint64_t label, const string& name, int64_t count)
|
||||
{
|
||||
string traceName = "H:" + name;
|
||||
AddBytraceMarker(MARKER_INT, label, traceName, std::to_string(count));
|
||||
}
|
||||
|
||||
void CountTraceDebug(uint64_t label, const string& name, int64_t count)
|
||||
{
|
||||
#if (TRACE_LEVEL >= DEBUG_LEVEL)
|
||||
string traceName = "H:" + name;
|
||||
AddBytraceMarker(MARKER_INT, label, traceName, std::to_string(count));
|
||||
#endif
|
||||
}
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
# Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//build/test.gni")
|
||||
import("//developtools/bytrace_standard/bytrace.gni")
|
||||
|
||||
module_output_path = "bytrace_standard/bytrace"
|
||||
|
||||
config("module_private_config") {
|
||||
visibility = [ ":*" ]
|
||||
}
|
||||
|
||||
ohos_moduletest("BytraceNDKTest") {
|
||||
module_out_path = module_output_path
|
||||
sources = [ "moduletest/common/native/bytrace_ndk_test.cpp" ]
|
||||
deps = [
|
||||
"${bytrace_path}/bin:bytrace_capture_inner",
|
||||
"${innerkits_path}/native:bytrace_core",
|
||||
"//third_party/googletest:gtest_main",
|
||||
]
|
||||
external_deps = [
|
||||
"hiviewdfx_hilog_native:libhilog",
|
||||
"startup_l2:syspara",
|
||||
]
|
||||
include_dirs = [ "${innerkits_path}/bytrace/bytrace_native/include" ]
|
||||
}
|
||||
|
||||
group("moduletest") {
|
||||
testonly = true
|
||||
deps = [ ":BytraceNDKTest" ]
|
||||
}
|
||||
+677
@@ -0,0 +1,677 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <fcntl.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <hilog/log.h>
|
||||
#include "bytrace.h"
|
||||
#include "bytrace_capture.h"
|
||||
#include "parameters.h"
|
||||
|
||||
using namespace testing::ext;
|
||||
using namespace std;
|
||||
using namespace OHOS::HiviewDFX;
|
||||
namespace OHOS {
|
||||
namespace Developtools {
|
||||
namespace BytraceTest {
|
||||
const string TRACE_MARKER_PATH = "trace_marker";
|
||||
const string TRACING_ON_PATH = "tracing_on";
|
||||
const string TRACING_ON = "tracing_on";
|
||||
const string TRACE_PATH = "trace";
|
||||
const string TRACE_MARK_WRITE = "tracing_mark_write";
|
||||
const string TRACE_PATTERN = "\\s*(.*?)-(.*?)\\s+(.*?)\\[(\\d+?)\\]\\s+(.*?)\\s+((\\d+).(\\d+)?):\\s+"
|
||||
+ TRACE_MARK_WRITE + ": ";
|
||||
const string TRACE_START = TRACE_PATTERN + "B\\|(.*?)\\|H:";
|
||||
const string TRACE_FINISH = TRACE_PATTERN + "E\\|";
|
||||
const string TRACE_ASYNC_START = TRACE_PATTERN + "S\\|(.*?)\\|H:";
|
||||
const string TRACE_ASYNC_FINISH = TRACE_PATTERN + "F\\|(.*?)\\|H:";
|
||||
const string TRACE_COUNT = TRACE_PATTERN + "C\\|(.*?)\\|H:";
|
||||
const string TRACE_PROPERTY = "debug.bytrace.tags.enableflags";
|
||||
constexpr uint32_t TASK = 1;
|
||||
constexpr uint32_t TID = 2;
|
||||
constexpr uint32_t TGID = 3;
|
||||
constexpr uint32_t CPU = 4;
|
||||
constexpr uint32_t DNH2 = 5;
|
||||
constexpr uint32_t TIMESTAMP = 6;
|
||||
constexpr uint32_t PID = 9;
|
||||
constexpr uint32_t TRACE_NAME = 10;
|
||||
constexpr uint32_t NUM = 11;
|
||||
|
||||
constexpr uint32_t TRACE_FMA11 = 11;
|
||||
constexpr uint32_t TRACE_FMA12 = 12;
|
||||
|
||||
constexpr uint64_t TRACE_INVALIDATE_TAG = 0x1000000;
|
||||
constexpr uint64_t BYTRACE_TAG = 0xd03301;
|
||||
const constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, BYTRACE_TAG, "BYTRACE_TEST"};
|
||||
const uint64_t TAG = BYTRACE_TAG_OHOS;
|
||||
static string g_traceRootPath;
|
||||
|
||||
bool SetProperty(const string& property, const string& value);
|
||||
string GetProperty(const string& property, const string& value);
|
||||
bool CleanTrace();
|
||||
bool CleanFtrace();
|
||||
bool SetFtrace(const string& filename, bool enabled);
|
||||
|
||||
class BytraceNDKTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase(void);
|
||||
static void TearDownTestCase(void);
|
||||
void SetUp();
|
||||
void TearDown(){};
|
||||
};
|
||||
|
||||
void BytraceNDKTest::SetUpTestCase()
|
||||
{
|
||||
const string debugfsDir = "/sys/kernel/debug/tracing/";
|
||||
const string tracefsDir = "/sys/kernel/tracing/";
|
||||
if (access((debugfsDir + TRACE_MARKER_PATH).c_str(), F_OK) != -1) {
|
||||
g_traceRootPath = debugfsDir;
|
||||
} else if (access((tracefsDir + TRACE_MARKER_PATH).c_str(), F_OK) != -1) {
|
||||
g_traceRootPath = tracefsDir;
|
||||
} else {
|
||||
HiLog::Error(LABEL, "Error: Finding trace folder failed");
|
||||
}
|
||||
CleanFtrace();
|
||||
}
|
||||
|
||||
void BytraceNDKTest::TearDownTestCase()
|
||||
{
|
||||
SetProperty(TRACE_PROPERTY, "0");
|
||||
SetFtrace(TRACING_ON, false);
|
||||
CleanTrace();
|
||||
}
|
||||
|
||||
void BytraceNDKTest::SetUp()
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
string value = to_string(TAG);
|
||||
SetProperty(TRACE_PROPERTY, value);
|
||||
HiLog::Info(LABEL, "current tag is %{public}s", GetProperty(TRACE_PROPERTY, "0").c_str());
|
||||
ASSERT_TRUE(GetProperty(TRACE_PROPERTY, "-123") == value);
|
||||
UpdateTraceLabel();
|
||||
}
|
||||
|
||||
struct Param {
|
||||
string m_task;
|
||||
string m_tid;
|
||||
string m_tgid;
|
||||
string m_cpu;
|
||||
string m_dnh2;
|
||||
string m_timestamp;
|
||||
string m_pid;
|
||||
string m_traceName;
|
||||
string m_num;
|
||||
};
|
||||
|
||||
class MyTrace {
|
||||
Param m_param;
|
||||
bool m_loaded;
|
||||
public:
|
||||
MyTrace() : m_loaded(false)
|
||||
{
|
||||
m_param.m_task = "";
|
||||
m_param.m_tid = "";
|
||||
m_param.m_tgid = "";
|
||||
m_param.m_cpu = "";
|
||||
m_param.m_dnh2 = "";
|
||||
m_param.m_timestamp = "";
|
||||
m_param.m_pid = "";
|
||||
m_param.m_traceName = "";
|
||||
m_param.m_num = "";
|
||||
}
|
||||
|
||||
~MyTrace()
|
||||
{
|
||||
}
|
||||
|
||||
// task-pid ( tig) [cpu] ...1 timestamp: tracing_mark_write: B|pid|traceName
|
||||
// task-pid ( tig) [cpu] ...1 timestamp: tracing_mark_write: E|pid
|
||||
void Load(const Param& param)
|
||||
{
|
||||
m_param.m_task = param.m_task;
|
||||
m_param.m_pid = param.m_pid;
|
||||
m_param.m_tid = param.m_tid;
|
||||
m_param.m_tgid = param.m_tgid;
|
||||
m_param.m_cpu = param.m_cpu;
|
||||
m_param.m_dnh2 = param.m_dnh2;
|
||||
m_param.m_timestamp = param.m_timestamp;
|
||||
m_param.m_traceName = param.m_traceName;
|
||||
m_param.m_num = param.m_num;
|
||||
m_loaded = true;
|
||||
}
|
||||
|
||||
string GetTask()
|
||||
{
|
||||
return m_param.m_task;
|
||||
}
|
||||
|
||||
string GetPid()
|
||||
{
|
||||
if (m_loaded) {
|
||||
return m_param.m_pid;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetTgid()
|
||||
{
|
||||
if (m_loaded) {
|
||||
return m_param.m_tgid;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetCpu()
|
||||
{
|
||||
if (m_loaded) {
|
||||
return m_param.m_cpu;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetDnh2()
|
||||
{
|
||||
if (m_loaded) {
|
||||
return m_param.m_dnh2;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetTimestamp()
|
||||
{
|
||||
if (m_loaded) {
|
||||
return m_param.m_timestamp;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetTraceName()
|
||||
{
|
||||
if (m_loaded) {
|
||||
return m_param.m_traceName;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetNum()
|
||||
{
|
||||
if (m_loaded) {
|
||||
return m_param.m_num;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string GetTid()
|
||||
{
|
||||
if (m_loaded) {
|
||||
return m_param.m_tid;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool IsLoaded() const
|
||||
{
|
||||
return m_loaded;
|
||||
}
|
||||
};
|
||||
|
||||
bool SetProperty(const string& property, const string& value)
|
||||
{
|
||||
bool result = false;
|
||||
result = OHOS::system::SetParameter(property, value);
|
||||
if (!result) {
|
||||
HiLog::Error(LABEL, "Error: setting %s failed", property.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string GetProperty(const string& property, const string& value)
|
||||
{
|
||||
return OHOS::system::GetParameter(property, value);
|
||||
}
|
||||
|
||||
bool GetTimeDuration(int64_t time1, int64_t time2, int64_t diffRange)
|
||||
{
|
||||
int64_t duration = time2 - time1;
|
||||
return (duration > 0) && (duration <= diffRange ? true : false);
|
||||
}
|
||||
|
||||
string& Trim(string& s)
|
||||
{
|
||||
if (s.empty()) {
|
||||
return s;
|
||||
}
|
||||
s.erase(0, s.find_first_not_of(" "));
|
||||
s.erase(s.find_last_not_of(" ") + 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
int64_t GetTimeStamp(string str)
|
||||
{
|
||||
if (str == "") {
|
||||
return 0;
|
||||
}
|
||||
int64_t time;
|
||||
Trim(str);
|
||||
time = atol(str.erase(str.find("."), 1).c_str());
|
||||
return time;
|
||||
}
|
||||
|
||||
MyTrace GetTraceResult(const string& checkContent, const vector<string>& list)
|
||||
{
|
||||
MyTrace trace;
|
||||
if (list.empty() || checkContent == "") {
|
||||
return trace;
|
||||
}
|
||||
regex pattern(checkContent);
|
||||
smatch match;
|
||||
Param param {""};
|
||||
for (int i = list.size() - 1; i >= 0; i--) {
|
||||
if (regex_match(list[i], match, pattern)) {
|
||||
param.m_task = match[TASK];
|
||||
param.m_tid = match[TID];
|
||||
param.m_tgid = match[TGID];
|
||||
param.m_cpu = match[CPU];
|
||||
param.m_dnh2 = match[DNH2];
|
||||
param.m_timestamp = match[TIMESTAMP];
|
||||
param.m_pid = match[PID];
|
||||
if (match.size() == TRACE_FMA11) {
|
||||
param.m_traceName = match[TRACE_NAME],
|
||||
param.m_num = "";
|
||||
} else if (match.size() == TRACE_FMA12) {
|
||||
param.m_traceName = match[TRACE_NAME],
|
||||
param.m_num = match[NUM];
|
||||
} else {
|
||||
param.m_traceName = "";
|
||||
param.m_num = "";
|
||||
}
|
||||
trace.Load(param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
|
||||
static bool WriteStringToFile(const string& fileName, const string& str)
|
||||
{
|
||||
if (g_traceRootPath.empty()) {
|
||||
HiLog::Error(LABEL, "Error: trace path not found.");
|
||||
return false;
|
||||
}
|
||||
ofstream out;
|
||||
out.open(g_traceRootPath + fileName, ios::out);
|
||||
out << str;
|
||||
out.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CleanTrace()
|
||||
{
|
||||
if (g_traceRootPath.empty()) {
|
||||
HiLog::Error(LABEL, "Error: trace path not found.");
|
||||
return false;
|
||||
}
|
||||
ofstream ofs;
|
||||
ofs.open(g_traceRootPath + TRACE_PATH, ofstream::out);
|
||||
if (!ofs.is_open()) {
|
||||
HiLog::Error(LABEL, "Error: opening trace path failed.");
|
||||
return false;
|
||||
}
|
||||
ofs << "";
|
||||
ofs.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
static stringstream ReadFile(const string& filename)
|
||||
{
|
||||
ifstream fin(filename.c_str());
|
||||
stringstream ss;
|
||||
if (!fin.is_open()) {
|
||||
fprintf(stderr, "opening file: %s failed!", filename.c_str());
|
||||
return ss;
|
||||
}
|
||||
ss << fin.rdbuf();
|
||||
fin.close();
|
||||
return ss;
|
||||
}
|
||||
|
||||
static bool IsFileExisting(const string& filename)
|
||||
{
|
||||
return access(filename.c_str(), F_OK) != -1;
|
||||
}
|
||||
|
||||
bool SetFtrace(const string& filename, bool enabled)
|
||||
{
|
||||
return WriteStringToFile(filename, enabled ? "1" : "0");
|
||||
}
|
||||
|
||||
bool CleanFtrace()
|
||||
{
|
||||
return WriteStringToFile("set_event", "");
|
||||
}
|
||||
|
||||
string GetFinishTraceRegex(MyTrace& trace)
|
||||
{
|
||||
if (!trace.IsLoaded()) {
|
||||
return "";
|
||||
} else {
|
||||
return "\\s*(.*?)-(" + trace.GetTid() + "?)\\s+(.*?)\\[(\\d+?)\\]\\s+(.*?)\\s+" + "((\\d+).(\\d+)?):\\s+" +
|
||||
TRACE_MARK_WRITE + ": E\\|(" + trace.GetPid() + ")|(.*)";
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> ReadFile2string(const string& filename)
|
||||
{
|
||||
vector<string> list;
|
||||
if (IsFileExisting(filename)) {
|
||||
stringstream ss = ReadFile(filename);
|
||||
string line;
|
||||
while (getline(ss, line)) {
|
||||
list.emplace_back(move(line));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
vector<string> ReadTrace()
|
||||
{
|
||||
return ReadFile2string(g_traceRootPath + TRACE_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node normal output start tracing and end tracing.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_001, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartTrace(TAG, "StartTraceTest001");
|
||||
FinishTrace(TAG, "StartTraceTest001");
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace startTrace = GetTraceResult(TRACE_START + "(StartTraceTest001) ", list);
|
||||
ASSERT_TRUE(startTrace.IsLoaded()) << "Can't find \"B|pid|StartTraceTest001\" from trace.";
|
||||
MyTrace finishTrace = GetTraceResult(GetFinishTraceRegex(startTrace), list);
|
||||
ASSERT_TRUE(finishTrace.IsLoaded()) << "Can't find \"E|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node has no output.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_002, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartTrace(TAG, "StartTraceTest002");
|
||||
FinishTrace(TAG, "StartTraceTest002");
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace startTrace = GetTraceResult(TRACE_START + "(StartTraceTest002) ", list);
|
||||
ASSERT_TRUE(startTrace.IsLoaded()) << "Can't find \"B|pid|StartTraceTest002\" from trace.";
|
||||
MyTrace finishTrace = GetTraceResult(GetFinishTraceRegex(startTrace), list);
|
||||
ASSERT_TRUE(finishTrace.IsLoaded()) << "Can't find \"E|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node normal output start trace and end trace.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_003, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartTrace(TAG, "StartTraceTest003 %s");
|
||||
FinishTrace(TAG, "StartTraceTest003 %s");
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace startTrace = GetTraceResult(TRACE_START + "(StartTraceTest003 %s) ", list);
|
||||
ASSERT_TRUE(startTrace.IsLoaded()) << "Can't find \"B|pid|StartTraceTest003 %s\" from trace.";
|
||||
MyTrace finishTrace = GetTraceResult(GetFinishTraceRegex(startTrace), list);
|
||||
ASSERT_TRUE(finishTrace.IsLoaded()) << "Can't find \"E|\" from trace.";
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
list.clear();
|
||||
StartTrace(TAG, "StartTraceTest003 %p");
|
||||
FinishTrace(TAG, "StartTraceTest003 %p");
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
list = ReadTrace();
|
||||
MyTrace startTrace2 = GetTraceResult(TRACE_START + "(StartTraceTest003 %p) ", list);
|
||||
MyTrace finishTrace2 = GetTraceResult(GetFinishTraceRegex(startTrace), list);
|
||||
ASSERT_TRUE(finishTrace2.IsLoaded()) << "Can't find \"E|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: test Input and output interval 1ms execution, time fluctuation 1ms
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_004, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartTrace(TAG, "StartTraceTest004");
|
||||
usleep(1000);
|
||||
FinishTrace(TAG, "StartTraceTest004");
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace startTrace = GetTraceResult(TRACE_START + "(StartTraceTest004) ", list);
|
||||
ASSERT_TRUE(startTrace.IsLoaded()) << "Can't find \"B|pid|StartTraceTest004\" from trace.";
|
||||
MyTrace finishTrace = GetTraceResult(GetFinishTraceRegex(startTrace), list);
|
||||
ASSERT_TRUE(finishTrace.IsLoaded()) << "Can't find \"E|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node normal output start trace and end trace
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_005, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartAsyncTrace(TAG, "asyncTraceTest005", 123);
|
||||
FinishAsyncTrace(TAG, "asyncTraceTest005", 123);
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace startTrace = GetTraceResult(TRACE_ASYNC_START + "(asyncTraceTest005) (.*)", list);
|
||||
ASSERT_TRUE(startTrace.IsLoaded()) << "Can't find \"S|pid|asyncTraceTest005\" from trace.";
|
||||
MyTrace finishTrace =
|
||||
GetTraceResult(TRACE_ASYNC_FINISH + startTrace.GetTraceName() + " " + startTrace.GetNum(), list);
|
||||
ASSERT_TRUE(finishTrace.IsLoaded()) << "Can't find \"F|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node normal output start trace and end trace
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_006, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
CountTrace(TAG, "countTraceTest006", 1);
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace countTrace = GetTraceResult(TRACE_COUNT + "(countTraceTest006) (.*)", list);
|
||||
ASSERT_TRUE(countTrace.IsLoaded()) << "Can't find \"C|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node normal output start trace and end trace.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_007, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartTrace(TRACE_INVALIDATE_TAG, "StartTraceTest007");
|
||||
FinishTrace(TRACE_INVALIDATE_TAG, "StartTraceTest007");
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace startTrace = GetTraceResult(TRACE_START + "(StartTraceTest007)", list);
|
||||
EXPECT_FALSE(startTrace.IsLoaded()) << "Can't find \"B|pid|StartTraceTest007\" from trace.";
|
||||
MyTrace finishTrace = GetTraceResult(GetFinishTraceRegex(startTrace), list);
|
||||
EXPECT_FALSE(finishTrace.IsLoaded()) << "Can't find \"E|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node normal output start trace and end trace.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_008, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartTrace(TRACE_INVALIDATE_TAG, "StartTraceTest008 %s");
|
||||
FinishTrace(TRACE_INVALIDATE_TAG, "StartTraceTest008 %s");
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace startTrace = GetTraceResult(TRACE_START + "(StartTraceTest008 %s)", list);
|
||||
EXPECT_FALSE(startTrace.IsLoaded()) << "Can't find \"B|pid|StartTraceTest008 %s\" from trace.";
|
||||
MyTrace finishTrace = GetTraceResult(GetFinishTraceRegex(startTrace), list);
|
||||
EXPECT_FALSE(finishTrace.IsLoaded()) << "Can't find \"E|\" from trace.";
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
list.clear();
|
||||
StartTrace(TRACE_INVALIDATE_TAG, "StartTraceTest008 %p");
|
||||
FinishTrace(TRACE_INVALIDATE_TAG, "StartTraceTest008 %p");
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
list = ReadTrace();
|
||||
MyTrace startTrace2 = GetTraceResult(TRACE_START + "(StartTraceTest008 %p)", list);
|
||||
MyTrace finishTrace2 = GetTraceResult(GetFinishTraceRegex(startTrace), list);
|
||||
EXPECT_FALSE(finishTrace2.IsLoaded()) << "Can't find \"E|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node normal output start trace and end trace
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_009, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartAsyncTrace(TRACE_INVALIDATE_TAG, "asyncTraceTest009", 123);
|
||||
FinishAsyncTrace(TRACE_INVALIDATE_TAG, "asyncTraceTest009", 123);
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace startTrace = GetTraceResult(TRACE_ASYNC_START + "(asyncTraceTest009)\\|(.*)", list);
|
||||
EXPECT_FALSE(startTrace.IsLoaded()) << "Can't find \"S|pid|asyncTraceTest009\" from trace.";
|
||||
MyTrace finishTrace = GetTraceResult(TRACE_ASYNC_FINISH + startTrace.GetTraceName() + "\\|"
|
||||
+ startTrace.GetNum(), list);
|
||||
EXPECT_FALSE(finishTrace.IsLoaded()) << "Can't find \"F|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node normal output start trace and end trace
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_010, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
CountTrace(TRACE_INVALIDATE_TAG, "countTraceTest010", 1);
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, false)) << "Setting tracing_on failed.";
|
||||
vector<string> list = ReadTrace();
|
||||
MyTrace countTrace = GetTraceResult(TRACE_COUNT + "(countTraceTest010)\\|(.*)", list);
|
||||
EXPECT_FALSE(countTrace.IsLoaded()) << "Can't find \"C|\" from trace.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node general output start and end tracing for debugging.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_011, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartTraceDebug(TAG, "StartTraceTest011");
|
||||
FinishTraceDebug(TAG, "StartTraceTest011");
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: tracing_mark_write file node general output start and end tracing for debugging.
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_012, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartTraceDebug(TAG, "StartTraceTest012 %s");
|
||||
FinishTraceDebug(TAG, "StartTraceTest012 %s");
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: Testing StartAsyncTraceDebug and FinishAsyncTraceDebug functions
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_013, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
StartAsyncTraceDebug(TAG, "asyncTraceTest013", 123);
|
||||
FinishAsyncTraceDebug(TAG, "asyncTraceTest013", 123);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: Testing CountTraceDebug function
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_014, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
CountTraceDebug(TAG, "countTraceTest014", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: Testing MiddleTrace function
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_015, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
MiddleTrace(TAG, "MiddleTraceTest015", "050tseTecarTelddiM");
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: bytrace
|
||||
* @tc.desc: Testing MiddleTraceDebug function
|
||||
* @tc.type: FUNC
|
||||
*/
|
||||
HWTEST_F(BytraceNDKTest, StartTrace_016, TestSize.Level1)
|
||||
{
|
||||
ASSERT_TRUE(CleanTrace());
|
||||
ASSERT_TRUE(SetFtrace(TRACING_ON, true)) << "Setting tracing_on failed.";
|
||||
MiddleTraceDebug(TAG, "MiddleTraceTest016", "061tseTecarTelddiM");
|
||||
}
|
||||
} // namespace BytraceTest
|
||||
} // namespace Developtools
|
||||
} // namespace OHOS
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
# Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
bytrace_path = "//developtools/bytrace_standard"
|
||||
|
||||
innerkits_path = "${bytrace_path}/interfaces/innerkits"
|
||||
|
||||
kits_path = "${bytrace_path}/interfaces/kits"
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 7.9 KiB |
Executable
+18
@@ -0,0 +1,18 @@
|
||||
# Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//build/ohos.gni")
|
||||
|
||||
group("innerkits_target") {
|
||||
deps = [ "native:bytrace_core" ]
|
||||
}
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
# Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//build/ohos.gni")
|
||||
import("//developtools/bytrace_standard/bytrace.gni")
|
||||
|
||||
config("bytrace_config") {
|
||||
visibility = [ ":*" ]
|
||||
include_dirs = [ "include" ]
|
||||
}
|
||||
|
||||
ohos_shared_library("bytrace_core") {
|
||||
public_configs = [ ":bytrace_config" ]
|
||||
deps = [ "${bytrace_path}/bin:bytrace_inner" ]
|
||||
subsystem_name = "developtools"
|
||||
part_name = "bytrace_standard"
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef DEVELOPTOOLS_INTERFACES_INNERKITS_BYTRACE_INCLUDE_BYTRACE_H
|
||||
#define DEVELOPTOOLS_INTERFACES_INNERKITS_BYTRACE_INCLUDE_BYTRACE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
constexpr uint64_t BYTRACE_TAG_NEVER = 0; // This tag is never enabled.
|
||||
constexpr uint64_t BYTRACE_TAG_ALWAYS = (1ULL << 0); // This tag is always enabled.
|
||||
constexpr uint64_t BYTRACE_TAG_OHOS = (1ULL << 30); // OHOS generic tag.
|
||||
constexpr uint64_t BYTRACE_TAG_ABILITY_MANAGER = (1ULL << 31); // Ability Manager tag.
|
||||
constexpr uint64_t BYTRACE_TAG_ZCAMERA = (1ULL << 32); // Camera module tag.
|
||||
constexpr uint64_t BYTRACE_TAG_ZMEDIA = (1ULL << 33); // Media module tag.
|
||||
constexpr uint64_t BYTRACE_TAG_ZIMAGE = (1ULL << 34); // Image module tag.
|
||||
constexpr uint64_t BYTRACE_TAG_ZAUDIO = (1ULL << 35); // Audio module tag.
|
||||
constexpr uint64_t BYTRACE_TAG_DISTRIBUTEDDATA = (1ULL << 36); // Distributeddata manager module tag.
|
||||
constexpr uint64_t BYTRACE_TAG_MDFS = (1ULL << 37); // Mobile distributed file system tag.
|
||||
constexpr uint64_t BYTRACE_TAG_GRAPHIC_AGP = (1ULL << 38); // Graphic module tag.
|
||||
constexpr uint64_t BYTRACE_TAG_ACE = (1ULL << 39); // ACE development framework tag.
|
||||
constexpr uint64_t BYTRACE_TAG_NOTIFICATION = (1ULL << 40); // Notification module tag.
|
||||
constexpr uint64_t BYTRACE_TAG_APP = (1ULL << 62); // App tag.
|
||||
|
||||
constexpr uint64_t BYTRACE_TAG_LAST = BYTRACE_TAG_APP;
|
||||
constexpr uint64_t BYTRACE_TAG_NOT_READY = (1ULL << 63); // Reserved for initialization.
|
||||
constexpr uint64_t BYTRACE_TAG_VALID_MASK = ((BYTRACE_TAG_LAST - 1) | BYTRACE_TAG_LAST);
|
||||
|
||||
#ifndef BYTRACE_TAG
|
||||
#define BYTRACE_TAG BYTRACE_TAG_NEVER
|
||||
#elif BYTRACE_TAG > BYTRACE_TAG_VALID_MASK
|
||||
#error BYTRACE_TAG must be defined to be one of the tags defined in bytrace.h
|
||||
#elif BYTRACE_TAG < BYTRACE_TAG_OHOS
|
||||
#error BYTRACE_TAG must be defined to be one of the tags defined in bytrace.h
|
||||
#endif
|
||||
|
||||
#define RELEASE_LEVEL 0X01
|
||||
#define DEBUG_LEVEL 0X02
|
||||
|
||||
#ifndef TRACE_LEVEL
|
||||
#define TRACE_LEVEL RELEASE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Update trace label when your process has started.
|
||||
*/
|
||||
void UpdateTraceLabel();
|
||||
|
||||
/**
|
||||
* Track the beginning of a context.
|
||||
*/
|
||||
void StartTrace(uint64_t label, const std::string& value, float limit = -1);
|
||||
void StartTraceDebug(uint64_t label, const std::string& value, float limit = -1);
|
||||
/**
|
||||
* Track the end of a context.
|
||||
*/
|
||||
void FinishTrace(uint64_t label, const std::string& value);
|
||||
void FinishTraceDebug(uint64_t label, const std::string& value);
|
||||
/**
|
||||
* Track the beginning of an asynchronous event.
|
||||
*/
|
||||
void StartAsyncTrace(uint64_t label, const std::string& value, int32_t taskId, float limit = -1);
|
||||
void StartAsyncTraceDebug(uint64_t label, const std::string& value, int32_t taskId, float limit = -1);
|
||||
|
||||
/**
|
||||
* Track the end of an asynchronous event.
|
||||
*/
|
||||
void FinishAsyncTrace(uint64_t label, const std::string& value, int32_t taskId);
|
||||
void FinishAsyncTraceDebug(uint64_t label, const std::string& value, int32_t taskId);
|
||||
|
||||
/**
|
||||
* Track the middle of a context. Match the previous function of StartTrace before it.
|
||||
*/
|
||||
void MiddleTrace(uint64_t label, const std::string& beforeValue, const std::string& afterValue);
|
||||
void MiddleTraceDebug(uint64_t label, const std::string& beforeValue, const std::string& afterValue);
|
||||
|
||||
/**
|
||||
* Track the 64-bit integer counter value.
|
||||
*/
|
||||
void CountTrace(uint64_t label, const std::string& name, int64_t count);
|
||||
void CountTraceDebug(uint64_t label, const std::string& name, int64_t count);
|
||||
|
||||
__END_DECLS
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // DEVELOPTOOLS_INTERFACES_INNERKITS_BYTRACE_INCLUDE_BYTRACE_H
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provides interfaces to generate {@code ByTrace} logs.
|
||||
*
|
||||
* <p>This class traces the start, end, and value changes of key processes that last for at least 3 ms.
|
||||
*
|
||||
* <p>Example:
|
||||
* To trace a name verification that is expected to complete within 5 ms:
|
||||
* <pre>{@code
|
||||
* Bytrace.startTrace("checkName", "5");
|
||||
* Bytrace.finishTrace("checkName");
|
||||
* }</pre>
|
||||
* To trace the number of layers, which is 3:
|
||||
* <pre>{@code
|
||||
* Bytrace.count("curLayer", 3);
|
||||
* }</pre>
|
||||
*
|
||||
* <p>Each {@code startTrace} matches one {@code finishTrace}, and they must have the same value.
|
||||
*
|
||||
* @since 1
|
||||
*/
|
||||
declare namespace bytrace {
|
||||
/**
|
||||
* Updates the trace label when your process has started.
|
||||
*/
|
||||
function updateTraceLabel(): void;
|
||||
|
||||
/**
|
||||
* Records a trace with the expected completion time and marks it as the start of a task.
|
||||
*
|
||||
* This method is invoked at the start of a transaction to indicate that a task whose name is specified by
|
||||
* {@code value} has started. The {@link #finishTrace(String)} method using the same {@code value} must be
|
||||
* invoked at the end of the transaction.
|
||||
*
|
||||
* @param value Indicates the operation name.
|
||||
* @param limit Indicates the expected time required for completing the operation, in milliseconds.
|
||||
*/
|
||||
function startTrace(value: string, limit: number): void;
|
||||
|
||||
/**
|
||||
* Track the middle of a context. Match the previous function of StartTrace before it.
|
||||
*
|
||||
* @param beforeValue Indicates the matched startTrace vlaue.
|
||||
* @param afterValue Indicates the matched finishTrace value.
|
||||
*/
|
||||
function middleTrace(beforeValue: string, afterValue: string): void;
|
||||
|
||||
/**
|
||||
* Records a trace and marks it as the end of a task.
|
||||
*
|
||||
* This method is invoked at the end of a transaction to indicate that a task whose name is specified by
|
||||
* {@code value} has ended. This method must be invoked after the {@link #startTrace(String, float)} or
|
||||
* {@link #startTrace(String)} method is invoked.
|
||||
*
|
||||
* @param value Indicates the operation name. It must be the same as the {@code value} of
|
||||
* {@link #startTrace(String, float)} or {@link #startTrace(String)}.
|
||||
*
|
||||
*/
|
||||
function finishTrace(value: string): void;
|
||||
|
||||
/**
|
||||
* Writes a async trace message and mark as start spot. The name and cookie
|
||||
* used to begin an event must be used to end it.
|
||||
*
|
||||
* @param value Message content.
|
||||
* @param taskId Unique identifier for distinguishing simultaneous events.
|
||||
* @param limit It is expected that the operation will be completed within the specified time period.
|
||||
*/
|
||||
function startAsyncTrace(value: string, taskId: number, limit: number): void;
|
||||
|
||||
/**
|
||||
* Writes a async trace message and mark as start spot. The name and cookie
|
||||
* used to begin an event must be used to end it.
|
||||
*
|
||||
* @param value Message content.
|
||||
* @param taskId Unique identifier for distinguishing simultaneous events.
|
||||
*/
|
||||
function finishAsyncTrace(value: string, taskId: number): void;
|
||||
|
||||
/**
|
||||
* Records a trace for generating a count, such as clock pulse and the number of layers.
|
||||
*
|
||||
* @param name Indicates the operation name.
|
||||
* @param count Indicates the count of the operation.
|
||||
*/
|
||||
function countTrace(name: string, count: number): void;
|
||||
}
|
||||
export default bytrace;
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"subsystem": "developtools",
|
||||
"parts": {
|
||||
"bytrace_standard": {
|
||||
"module_list": [
|
||||
"//developtools/bytrace_standard/interfaces/innerkits/native:bytrace_core",
|
||||
"//developtools/bytrace_standard/bin:bytrace_target"
|
||||
],
|
||||
"inner_kits": [
|
||||
{
|
||||
"type": "so",
|
||||
"name": "//developtools/bytrace_standard/interfaces/innerkits/native:bytrace_core",
|
||||
"header": {
|
||||
"header_files": [
|
||||
"bytrace.h"
|
||||
],
|
||||
"header_base": "//developtools/bytrace_standard/interfaces/innerkits/native/include"
|
||||
}
|
||||
}
|
||||
],
|
||||
"test_list": [
|
||||
"//developtools/bytrace_standard/bin/test:moduletest"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
@rem Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem http://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
|
||||
@echo off
|
||||
hdc shell "echo > /sys/kernel/debug/tracing/trace"
|
||||
hdc shell "echo 4096 > /d/tracing/saved_cmdlines_size"
|
||||
hdc shell "bytrace -t 10 -b 4096 --overwrite ohos zimage zmedia zcamera zaudio ability distributeddatamgr sched freq irq workq rs idle load disk pagecache memreclaim > /data/mynewtrace.ftrace"
|
||||
hdc shell "echo > /sys/kernel/debug/tracing/trace"
|
||||
hdc shell "sed -i '1,2d' /data/mynewtrace.ftrace"
|
||||
hdc pull /data/mynewtrace.ftrace .
|
||||
pause
|
||||
Executable
+136
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2021 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import codecs
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
files = []
|
||||
trace_regex = "\s*(.*?)-(\d+?)\s+\(\s*(\d+?)\)\s+\[\d+\]\s+(.*?)\s+(.*?):\s+"
|
||||
all_traces_dict = {} # {"deviceName": [(timestamp, line) ...]}
|
||||
all_real_time_dict = {}
|
||||
default_real_time = 7983849599000 # 2222-12-31 23:59:59
|
||||
|
||||
def compare_timestamp(time1, time2):
|
||||
return float(time1) < float(time2)
|
||||
|
||||
def read_files(file, devices_name):
|
||||
traces = []
|
||||
with codecs.open(file, 'r', encoding='utf-8') as fp:
|
||||
for line in fp:
|
||||
if line.find("binder_transaction") > -1 \
|
||||
or line.find("tracing_mark_write") > -1:
|
||||
line = line.replace("\n", "")
|
||||
trace_match = re.match(trace_regex, line)
|
||||
if trace_match:
|
||||
traces.append((float(trace_match.group(5)), line))
|
||||
if line.find("realtime_ts") > -1:
|
||||
time_regex = trace_regex + \
|
||||
"tracing_mark_write:\s+trace_event_clock_sync: realtime_ts=(.*)"
|
||||
time_match = re.match(time_regex, line)
|
||||
all_real_time_dict[devices_name] = { \
|
||||
"realtime_ts": int(time_match.group(6)), \
|
||||
"timestamp": float(time_match.group(5))}
|
||||
if (not all_real_time_dict.__contains__(devices_name)) and traces:
|
||||
line = traces[-1][1]
|
||||
trace_match = re.match(trace_regex, line)
|
||||
all_real_time_dict[devices_name] = { \
|
||||
"realtime_ts": default_real_time, \
|
||||
"timestamp": float(trace_match.group(5))}
|
||||
return traces
|
||||
|
||||
def handle_option():
|
||||
if len(sys.argv) < 2:
|
||||
print("eg: python bytrace_multi.py file1.ftrace file2.ftrace ...")
|
||||
exit(0)
|
||||
for i in range(len(sys.argv)):
|
||||
if i == 0:
|
||||
continue
|
||||
if sys.argv[i] == "-h" or sys.argv[i] == "--help":
|
||||
print("eg: python bytrace_multi.py file1.ftrace file2.ftrace ...")
|
||||
exit(0)
|
||||
elif not os.path.exists(sys.argv[i]):
|
||||
print("Warning: {} is not found.".format(sys.argv[i]))
|
||||
else:
|
||||
files.append(sys.argv[i])
|
||||
|
||||
def change_trace_time(all_trace_list, \
|
||||
base_real_time, \
|
||||
base_time_stamp, \
|
||||
target_device):
|
||||
target_real_time = all_real_time_dict[target_device]["realtime_ts"]
|
||||
target_time_stamp = all_real_time_dict[target_device]["timestamp"]
|
||||
if not target_real_time == default_real_time:
|
||||
diff_real_time = float(target_real_time - base_real_time) / 1000
|
||||
target_time_stamp_ = base_time_stamp + diff_real_time
|
||||
diff_time = target_time_stamp - target_time_stamp_
|
||||
else:
|
||||
# If the file does not have realtime, the difference is 0.5s.
|
||||
diff_real_time = 0.5
|
||||
target_time_stamp_ = base_time_stamp + diff_real_time
|
||||
diff_time = target_time_stamp - target_time_stamp_
|
||||
traces = all_traces_dict[target_device]
|
||||
for mtuple in traces:
|
||||
timestamp = float(mtuple[0])
|
||||
line = mtuple[1]
|
||||
timestamp_ = "{:.6f}".format(timestamp - diff_time)
|
||||
line_ = target_device + \
|
||||
line.replace("{:.6f}".format(timestamp), str(timestamp_))
|
||||
all_trace_list.append((timestamp_, line_))
|
||||
|
||||
def write_to_file(data, file_name):
|
||||
with codecs.open(file_name, 'w+', encoding='utf-8') as fp:
|
||||
fp.write("# tracer: nop\n")
|
||||
fp.write("#\n")
|
||||
fp.write("# _-----=> irqs-off\n")
|
||||
fp.write("# / _----=> need-resched\n")
|
||||
fp.write("# | / _---=> hardirq/softirq\n")
|
||||
fp.write("# || / _--=> preempt-depth\n")
|
||||
fp.write("# ||| / delay\n")
|
||||
fp.write("# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION\n")
|
||||
fp.write("# | | | | |||| | |\n")
|
||||
for mtuple in data:
|
||||
fp.write(mtuple[1])
|
||||
fp.write("\n")
|
||||
|
||||
def main():
|
||||
handle_option()
|
||||
if len(files) == 0:
|
||||
exit(-1)
|
||||
|
||||
for i, val in enumerate(files):
|
||||
device_name = "[device_{}]".format(str(i))
|
||||
all_traces_dict[device_name] = read_files(val, device_name)
|
||||
|
||||
all_time_sorted_list = sorted(all_real_time_dict.items(), key=lambda \
|
||||
all_real_time_dict: all_real_time_dict[1]["realtime_ts"])
|
||||
base_real_time = all_time_sorted_list[0][1]["realtime_ts"]
|
||||
base_time_stamp = all_time_sorted_list[0][1]["timestamp"]
|
||||
all_trace_list = [] # [(timestamp, line)]
|
||||
for mtuple in all_time_sorted_list:
|
||||
target_device = mtuple[0]
|
||||
change_trace_time(all_trace_list, \
|
||||
base_real_time, \
|
||||
base_time_stamp, \
|
||||
target_device)
|
||||
# Sort by timestamp from small to large
|
||||
all_trace_sorted_list = sorted(all_trace_list, key=lambda x: x[0])
|
||||
curtime = time.strftime("%Y%m%d_%H%M%S", time.localtime())
|
||||
write_to_file(all_trace_sorted_list, "multi_trace_"+str(curtime)+".ftrace")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user