update OpenHarmony 2.0 Canary

This commit is contained in:
mamingshuai
2021-06-02 00:04:31 +08:00
parent f252f31095
commit 801d4053c0
21 changed files with 2729 additions and 73 deletions
View File
Executable
+178
View File
@@ -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
-36
View File
@@ -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/)
-37
View File
@@ -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
View File
@@ -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>
![](figures/20210422-202314(WeLinkPC).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
View File
@@ -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" ]
}
+38
View File
@@ -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
+867
View File
@@ -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;
}
+42
View File
@@ -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;
}
+213
View File
@@ -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
}
+41
View File
@@ -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
View File
@@ -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
View File
@@ -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"
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

+18
View File
@@ -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" ]
}
+27
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
]
}
}
}
+21
View File
@@ -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
+136
View File
@@ -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()